diff --git a/arch_init.c b/arch_init.c index d4c92b0a456be86ba7fab50c1eeff9da8b0189c0..847bf4edd64e0647158cf6c8e87146cd9bb78ac8 100644 --- a/arch_init.c +++ b/arch_init.c @@ -41,6 +41,7 @@ #include "net.h" #include "gdbstub.h" #include "hw/smbios.h" +#include "exec-memory.h" #ifdef TARGET_SPARC int graphic_width = 1024; @@ -263,10 +264,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) return 0; } - if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) { - qemu_file_set_error(f, -EINVAL); - return -EINVAL; - } + memory_global_sync_dirty_bitmap(get_system_memory()); if (stage == 1) { RAMBlock *block; diff --git a/cpu-all.h b/cpu-all.h index 9d787151e1844aa8cabe9ab786738460bf7c8633..734833abda16d4965d9adfaec901c71da601cc19 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -569,15 +569,6 @@ int cpu_physical_memory_set_dirty_tracking(int enable); int cpu_physical_memory_get_dirty_tracking(void); -int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, - target_phys_addr_t end_addr); - -int cpu_physical_log_start(target_phys_addr_t start_addr, - ram_addr_t size); - -int cpu_physical_log_stop(target_phys_addr_t start_addr, - ram_addr_t size); - void dump_exec_info(FILE *f, fprintf_function cpu_fprintf); #endif /* !CONFIG_USER_ONLY */ diff --git a/cpu-common.h b/cpu-common.h index 8295e4fea4eceef55bfd78298802652dde0d5c2b..3fe44d25d1196e9bc0c3a48353f8bbe01b81e865 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -38,7 +38,6 @@ typedef unsigned long ram_addr_t; typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value); typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr); -ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr); void qemu_ram_remap(ram_addr_t addr, ram_addr_t length); /* This should only be used for ram local to a device. */ void *qemu_get_ram_ptr(ram_addr_t addr); @@ -71,29 +70,6 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque)); void cpu_unregister_map_client(void *cookie); -struct CPUPhysMemoryClient; -typedef struct CPUPhysMemoryClient CPUPhysMemoryClient; -struct CPUPhysMemoryClient { - void (*set_memory)(struct CPUPhysMemoryClient *client, - target_phys_addr_t start_addr, - ram_addr_t size, - ram_addr_t phys_offset, - bool log_dirty); - int (*sync_dirty_bitmap)(struct CPUPhysMemoryClient *client, - target_phys_addr_t start_addr, - target_phys_addr_t end_addr); - int (*migration_log)(struct CPUPhysMemoryClient *client, - int enable); - int (*log_start)(struct CPUPhysMemoryClient *client, - target_phys_addr_t phys_addr, ram_addr_t size); - int (*log_stop)(struct CPUPhysMemoryClient *client, - target_phys_addr_t phys_addr, ram_addr_t size); - QLIST_ENTRY(CPUPhysMemoryClient) list; -}; - -void cpu_register_phys_memory_client(CPUPhysMemoryClient *); -void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *); - /* Coalesced MMIO regions are areas where write operations can be reordered. * This usually implies that write operations are side-effect free. This allows * batching which can make a major impact on performance when using diff --git a/exec.c b/exec.c index 32782b48c9b9832bea5543e5a69f81a9ffec282d..b02199b271de70350cf135a2ed05cce5ce113f2c 100644 --- a/exec.c +++ b/exec.c @@ -1732,124 +1732,6 @@ const CPULogItem cpu_log_items[] = { { 0, NULL, NULL }, }; -#ifndef CONFIG_USER_ONLY -static QLIST_HEAD(memory_client_list, CPUPhysMemoryClient) memory_client_list - = QLIST_HEAD_INITIALIZER(memory_client_list); - -static void cpu_notify_set_memory(target_phys_addr_t start_addr, - ram_addr_t size, - ram_addr_t phys_offset, - bool log_dirty) -{ - CPUPhysMemoryClient *client; - QLIST_FOREACH(client, &memory_client_list, list) { - client->set_memory(client, start_addr, size, phys_offset, log_dirty); - } -} - -static int cpu_notify_sync_dirty_bitmap(target_phys_addr_t start, - target_phys_addr_t end) -{ - CPUPhysMemoryClient *client; - QLIST_FOREACH(client, &memory_client_list, list) { - int r = client->sync_dirty_bitmap(client, start, end); - if (r < 0) - return r; - } - return 0; -} - -static int cpu_notify_migration_log(int enable) -{ - CPUPhysMemoryClient *client; - QLIST_FOREACH(client, &memory_client_list, list) { - int r = client->migration_log(client, enable); - if (r < 0) - return r; - } - return 0; -} - -struct last_map { - target_phys_addr_t start_addr; - ram_addr_t size; - ram_addr_t phys_offset; -}; - -/* The l1_phys_map provides the upper P_L1_BITs of the guest physical - * address. Each intermediate table provides the next L2_BITs of guest - * physical address space. The number of levels vary based on host and - * guest configuration, making it efficient to build the final guest - * physical address by seeding the L1 offset and shifting and adding in - * each L2 offset as we recurse through them. */ -static void phys_page_for_each_1(CPUPhysMemoryClient *client, int level, - void **lp, target_phys_addr_t addr, - struct last_map *map) -{ - int i; - - if (*lp == NULL) { - return; - } - if (level == 0) { - PhysPageDesc *pd = *lp; - addr <<= L2_BITS + TARGET_PAGE_BITS; - for (i = 0; i < L2_SIZE; ++i) { - if (pd[i].phys_offset != IO_MEM_UNASSIGNED) { - target_phys_addr_t start_addr = addr | i << TARGET_PAGE_BITS; - - if (map->size && - start_addr == map->start_addr + map->size && - pd[i].phys_offset == map->phys_offset + map->size) { - - map->size += TARGET_PAGE_SIZE; - continue; - } else if (map->size) { - client->set_memory(client, map->start_addr, - map->size, map->phys_offset, false); - } - - map->start_addr = start_addr; - map->size = TARGET_PAGE_SIZE; - map->phys_offset = pd[i].phys_offset; - } - } - } else { - void **pp = *lp; - for (i = 0; i < L2_SIZE; ++i) { - phys_page_for_each_1(client, level - 1, pp + i, - (addr << L2_BITS) | i, map); - } - } -} - -static void phys_page_for_each(CPUPhysMemoryClient *client) -{ - int i; - struct last_map map = { }; - - for (i = 0; i < P_L1_SIZE; ++i) { - phys_page_for_each_1(client, P_L1_SHIFT / L2_BITS - 1, - l1_phys_map + i, i, &map); - } - if (map.size) { - client->set_memory(client, map.start_addr, map.size, map.phys_offset, - false); - } -} - -void cpu_register_phys_memory_client(CPUPhysMemoryClient *client) -{ - QLIST_INSERT_HEAD(&memory_client_list, client, list); - phys_page_for_each(client); -} - -void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *client) -{ - QLIST_REMOVE(client, list); -} -#endif - static int cmp1(const char *s1, int n, const char *s2) { if (strlen(s2) != n) @@ -2126,7 +2008,11 @@ int cpu_physical_memory_set_dirty_tracking(int enable) { int ret = 0; in_migration = enable; - ret = cpu_notify_migration_log(!!enable); + if (enable) { + memory_global_dirty_log_start(); + } else { + memory_global_dirty_log_stop(); + } return ret; } @@ -2135,45 +2021,6 @@ int cpu_physical_memory_get_dirty_tracking(void) return in_migration; } -int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, - target_phys_addr_t end_addr) -{ - int ret; - - ret = cpu_notify_sync_dirty_bitmap(start_addr, end_addr); - return ret; -} - -int cpu_physical_log_start(target_phys_addr_t start_addr, - ram_addr_t size) -{ - CPUPhysMemoryClient *client; - QLIST_FOREACH(client, &memory_client_list, list) { - if (client->log_start) { - int r = client->log_start(client, start_addr, size); - if (r < 0) { - return r; - } - } - } - return 0; -} - -int cpu_physical_log_stop(target_phys_addr_t start_addr, - ram_addr_t size) -{ - CPUPhysMemoryClient *client; - QLIST_FOREACH(client, &memory_client_list, list) { - if (client->log_stop) { - int r = client->log_stop(client, start_addr, size); - if (r < 0) { - return r; - } - } - } - return 0; -} - static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) { ram_addr_t ram_addr; @@ -2676,7 +2523,6 @@ void cpu_register_physical_memory_log(target_phys_addr_t start_addr, subpage_t *subpage; assert(size); - cpu_notify_set_memory(start_addr, size, phys_offset, log_dirty); if (phys_offset == IO_MEM_UNASSIGNED) { region_offset = start_addr; @@ -2749,17 +2595,6 @@ void cpu_register_physical_memory_log(target_phys_addr_t start_addr, } } -/* XXX: temporary until new memory mapping API */ -ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr) -{ - PhysPageDesc *p; - - p = phys_page_find(addr >> TARGET_PAGE_BITS); - if (!p) - return IO_MEM_UNASSIGNED; - return p->phys_offset; -} - void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) { if (kvm_enabled()) diff --git a/hw/framebuffer.c b/hw/framebuffer.c index 56cf16e27a977f84b92c81abc6162ba5366d5deb..b43bcdff40fc3491e20982e3cd8d8801901b7837 100644 --- a/hw/framebuffer.c +++ b/hw/framebuffer.c @@ -22,6 +22,7 @@ void framebuffer_update_display( DisplayState *ds, + MemoryRegion *address_space, target_phys_addr_t base, int cols, /* Width in pixels. */ int rows, /* Leight in pixels. */ @@ -42,28 +43,22 @@ void framebuffer_update_display( int dirty; int i; ram_addr_t addr; - ram_addr_t pd; - ram_addr_t pd2; + MemoryRegionSection mem_section; + MemoryRegion *mem; i = *first_row; *first_row = -1; src_len = src_width * rows; - cpu_physical_sync_dirty_bitmap(base, base + src_len); - pd = cpu_get_physical_page_desc(base); - pd2 = cpu_get_physical_page_desc(base + src_len - 1); - /* We should reall check that this is a continuous ram region. - Instead we just check that the first and last pages are - both ram, and the right distance apart. */ - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM - || (pd2 & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { - return; - } - pd = (pd & TARGET_PAGE_MASK) + (base & ~TARGET_PAGE_MASK); - if (((pd + src_len - 1) & TARGET_PAGE_MASK) != (pd2 & TARGET_PAGE_MASK)) { + mem_section = memory_region_find(address_space, base, src_len); + if (mem_section.size != src_len || !memory_region_is_ram(mem_section.mr)) { return; } + mem = mem_section.mr; + assert(mem); + assert(mem_section.offset_within_address_space == base); + memory_region_sync_dirty_bitmap(mem); src_base = cpu_physical_memory_map(base, &src_len, 0); /* If we can't map the framebuffer then bail. We could try harder, but it's not really worth it as dirty flag tracking will probably @@ -82,7 +77,7 @@ void framebuffer_update_display( dest -= dest_row_pitch * (rows - 1); } first = -1; - addr = pd; + addr = mem_section.offset_within_region; addr += i * src_width; src += i * src_width; @@ -93,8 +88,8 @@ void framebuffer_update_display( dirty = 0; dirty_offset = 0; while (addr + dirty_offset < TARGET_PAGE_ALIGN(addr + src_width)) { - dirty |= cpu_physical_memory_get_dirty(addr + dirty_offset, - VGA_DIRTY_FLAG); + dirty |= memory_region_get_dirty(mem, addr + dirty_offset, + DIRTY_MEMORY_VGA); dirty_offset += TARGET_PAGE_SIZE; } @@ -112,7 +107,8 @@ void framebuffer_update_display( if (first < 0) { return; } - cpu_physical_memory_reset_dirty(pd, pd + src_len, VGA_DIRTY_FLAG); + memory_region_reset_dirty(mem, mem_section.offset_within_region, src_len, + DIRTY_MEMORY_VGA); *first_row = first; *last_row = last; return; diff --git a/hw/framebuffer.h b/hw/framebuffer.h index a3a214649d26985902409a974fea498a5d3b7f67..527a6b85f812ffa56acda8660df25c1f461bb03f 100644 --- a/hw/framebuffer.h +++ b/hw/framebuffer.h @@ -1,12 +1,15 @@ #ifndef QEMU_FRAMEBUFFER_H #define QEMU_FRAMEBUFFER_H +#include "memory.h" + /* Framebuffer device helper routines. */ typedef void (*drawfn)(void *, uint8_t *, const uint8_t *, int, int); void framebuffer_update_display( DisplayState *ds, + MemoryRegion *address_space, target_phys_addr_t base, int cols, int rows, diff --git a/hw/loader.c b/hw/loader.c index 9bbcddd424b9b21558864cc2e444af88c6ef815f..446b62874ebc6c8192b9562a7f3ed8ea866266ec 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -49,6 +49,8 @@ #include "uboot_image.h" #include "loader.h" #include "fw_cfg.h" +#include "memory.h" +#include "exec-memory.h" #include @@ -674,7 +676,7 @@ static void rom_reset(void *unused) int rom_load_all(void) { target_phys_addr_t addr = 0; - int memtype; + MemoryRegionSection section; Rom *rom; QTAILQ_FOREACH(rom, &roms, next) { @@ -690,9 +692,8 @@ int rom_load_all(void) } addr = rom->addr; addr += rom->romsize; - memtype = cpu_get_physical_page_desc(rom->addr) & (3 << IO_MEM_SHIFT); - if (memtype == IO_MEM_ROM) - rom->isrom = 1; + section = memory_region_find(get_system_memory(), rom->addr, 1); + rom->isrom = section.size && memory_region_is_rom(section.mr); } qemu_register_reset(rom_reset, NULL); roms_loaded = 1; diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c index 01cd309ca3f6d09fba2e70a0ae2988f9be78435c..108115e300942972568c8ece40223cdddd07fa24 100644 --- a/hw/milkymist-vgafb.c +++ b/hw/milkymist-vgafb.c @@ -120,7 +120,7 @@ static void vgafb_update_display(void *opaque) break; } - framebuffer_update_display(s->ds, + framebuffer_update_display(s->ds, sysbus_address_space(&s->busdev), s->regs[R_BASEADDRESS] + s->fb_offset, s->regs[R_HRES], s->regs[R_VRES], diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index 8484f7058da4dcf04f2b6474d540afa27df7f782..f265306556c9c3385ed23d4aeb6d40d0aff7d32a 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -22,6 +22,7 @@ #include "framebuffer.h" struct omap_lcd_panel_s { + MemoryRegion *sysmem; MemoryRegion iomem; qemu_irq irq; DisplayState *state; @@ -211,7 +212,7 @@ static void omap_update_display(void *opaque) step = width * bpp >> 3; linesize = ds_get_linesize(omap_lcd->state); - framebuffer_update_display(omap_lcd->state, + framebuffer_update_display(omap_lcd->state, omap_lcd->sysmem, frame_base, width, height, step, linesize, 0, omap_lcd->invalidate, @@ -440,6 +441,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem, s->irq = irq; s->dma = dma; + s->sysmem = sysmem; omap_lcdc_reset(s); memory_region_init_io(&s->iomem, &omap_lcdc_ops, s, "omap.lcdc", 0x100); diff --git a/hw/pl110.c b/hw/pl110.c index cc1eb6d986a627bca3ed43473ebe3842b1d182cf..303a9bcdbdeb36ad788991d01d51d630587eba51 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -229,7 +229,7 @@ static void pl110_update_display(void *opaque) } dest_width *= s->cols; first = 0; - framebuffer_update_display(s->ds, + framebuffer_update_display(s->ds, sysbus_address_space(&s->busdev), s->upbase, s->cols, s->rows, src_width, dest_width, 0, s->invalidate, diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index fd23d63a649416ba36a76be228e5bf52689b51eb..5dd4ef06d66a6541b5fcc4fb90a5259d66465ea1 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -30,6 +30,7 @@ struct DMAChannel { }; struct PXA2xxLCDState { + MemoryRegion *sysmem; MemoryRegion iomem; qemu_irq irq; int irqlevel; @@ -681,7 +682,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s, dest_width = s->xres * s->dest_width; *miny = 0; - framebuffer_update_display(s->ds, + framebuffer_update_display(s->ds, s->sysmem, addr, s->xres, s->yres, src_width, dest_width, s->dest_width, s->invalidated, @@ -708,7 +709,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s, dest_width = s->yres * s->dest_width; *miny = 0; - framebuffer_update_display(s->ds, + framebuffer_update_display(s->ds, s->sysmem, addr, s->xres, s->yres, src_width, s->dest_width, -dest_width, s->invalidated, @@ -739,7 +740,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s, dest_width = s->xres * s->dest_width; *miny = 0; - framebuffer_update_display(s->ds, + framebuffer_update_display(s->ds, s->sysmem, addr, s->xres, s->yres, src_width, -dest_width, -s->dest_width, s->invalidated, @@ -769,7 +770,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s, dest_width = s->yres * s->dest_width; *miny = 0; - framebuffer_update_display(s->ds, + framebuffer_update_display(s->ds, s->sysmem, addr, s->xres, s->yres, src_width, -s->dest_width, dest_width, s->invalidated, @@ -985,6 +986,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState)); s->invalidated = 1; s->irq = irq; + s->sysmem = sysmem; pxa2xx_lcdc_orientation(s, graphic_rotate); diff --git a/hw/sysbus.c b/hw/sysbus.c index 24f619f65c09fac11ed857ed81c998a5e0df6ae3..2e06fe823c901c40ab751b318f0a0756d49e3a36 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -253,3 +253,8 @@ void sysbus_del_io(SysBusDevice *dev, MemoryRegion *mem) { memory_region_del_subregion(get_system_io(), mem); } + +MemoryRegion *sysbus_address_space(SysBusDevice *dev) +{ + return get_system_memory(); +} diff --git a/hw/sysbus.h b/hw/sysbus.h index 2f4025b22160e965ef70db1d60cc74d37f4dd4c1..899756bf7fdcaeeab5a477e0bbef5932c6718a91 100644 --- a/hw/sysbus.h +++ b/hw/sysbus.h @@ -57,6 +57,7 @@ void sysbus_del_memory(SysBusDevice *dev, MemoryRegion *mem); void sysbus_add_io(SysBusDevice *dev, target_phys_addr_t addr, MemoryRegion *mem); void sysbus_del_io(SysBusDevice *dev, MemoryRegion *mem); +MemoryRegion *sysbus_address_space(SysBusDevice *dev); /* Legacy helper function for creating devices. */ DeviceState *sysbus_create_varargs(const char *name, diff --git a/hw/vga.c b/hw/vga.c index ca79aa157dd0000fefa66c27415e17fef0ef5aed..7e1dd5ac809e7c09103057192468d677ed2d4a9d 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -28,6 +28,7 @@ #include "vga_int.h" #include "pixel_ops.h" #include "qemu-timer.h" +#include "xen.h" //#define DEBUG_VGA //#define DEBUG_VGA_MEM @@ -2222,6 +2223,7 @@ void vga_common_init(VGACommonState *s, int vga_ram_size) s->is_vbe_vmstate = 0; #endif memory_region_init_ram(&s->vram, NULL, "vga.vram", vga_ram_size); + xen_register_framebuffer(&s->vram); s->vram_ptr = memory_region_get_ram_ptr(&s->vram); s->vram_size = vga_ram_size; s->get_bpp = vga_get_bpp; diff --git a/hw/vhost.c b/hw/vhost.c index 0870cb7d8590db00fdc5ec880386665adc4b1a9e..cd56e75d0a6be62b0553b5013265eb26927bc1b0 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -17,6 +17,7 @@ #include static void vhost_dev_sync_region(struct vhost_dev *dev, + MemoryRegionSection *section, uint64_t mfirst, uint64_t mlast, uint64_t rfirst, uint64_t rlast) { @@ -49,38 +50,50 @@ static void vhost_dev_sync_region(struct vhost_dev *dev, ffsll(log) : ffs(log))) { ram_addr_t ram_addr; bit -= 1; - ram_addr = cpu_get_physical_page_desc(addr + bit * VHOST_LOG_PAGE); - cpu_physical_memory_set_dirty(ram_addr); + ram_addr = section->offset_within_region + bit * VHOST_LOG_PAGE; + memory_region_set_dirty(section->mr, ram_addr); log &= ~(0x1ull << bit); } addr += VHOST_LOG_CHUNK; } } -static int vhost_client_sync_dirty_bitmap(CPUPhysMemoryClient *client, - target_phys_addr_t start_addr, - target_phys_addr_t end_addr) +static int vhost_sync_dirty_bitmap(struct vhost_dev *dev, + MemoryRegionSection *section, + target_phys_addr_t start_addr, + target_phys_addr_t end_addr) { - struct vhost_dev *dev = container_of(client, struct vhost_dev, client); int i; + if (!dev->log_enabled || !dev->started) { return 0; } for (i = 0; i < dev->mem->nregions; ++i) { struct vhost_memory_region *reg = dev->mem->regions + i; - vhost_dev_sync_region(dev, start_addr, end_addr, + vhost_dev_sync_region(dev, section, start_addr, end_addr, reg->guest_phys_addr, range_get_last(reg->guest_phys_addr, reg->memory_size)); } for (i = 0; i < dev->nvqs; ++i) { struct vhost_virtqueue *vq = dev->vqs + i; - vhost_dev_sync_region(dev, start_addr, end_addr, vq->used_phys, + vhost_dev_sync_region(dev, section, start_addr, end_addr, vq->used_phys, range_get_last(vq->used_phys, vq->used_size)); } return 0; } +static void vhost_log_sync(MemoryListener *listener, + MemoryRegionSection *section) +{ + struct vhost_dev *dev = container_of(listener, struct vhost_dev, + memory_listener); + target_phys_addr_t start_addr = section->offset_within_address_space; + target_phys_addr_t end_addr = start_addr + section->size; + + vhost_sync_dirty_bitmap(dev, section, start_addr, end_addr); +} + /* Assign/unassign. Keep an unsorted array of non-overlapping * memory regions in dev->mem. */ static void vhost_dev_unassign_memory(struct vhost_dev *dev, @@ -250,7 +263,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size) { vhost_log_chunk_t *log; uint64_t log_base; - int r; + int r, i; if (size) { log = g_malloc0(size * sizeof *log); } else { @@ -259,8 +272,10 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size) log_base = (uint64_t)(unsigned long)log; r = ioctl(dev->control, VHOST_SET_LOG_BASE, &log_base); assert(r >= 0); - vhost_client_sync_dirty_bitmap(&dev->client, 0, - (target_phys_addr_t)~0x0ull); + for (i = 0; i < dev->n_mem_sections; ++i) { + vhost_sync_dirty_bitmap(dev, &dev->mem_sections[i], + 0, (target_phys_addr_t)~0x0ull); + } if (dev->log) { g_free(dev->log); } @@ -335,31 +350,37 @@ static bool vhost_dev_cmp_memory(struct vhost_dev *dev, return uaddr != reg->userspace_addr + start_addr - reg->guest_phys_addr; } -static void vhost_client_set_memory(CPUPhysMemoryClient *client, - target_phys_addr_t start_addr, - ram_addr_t size, - ram_addr_t phys_offset, - bool log_dirty) +static void vhost_set_memory(MemoryListener *listener, + MemoryRegionSection *section, + bool add) { - struct vhost_dev *dev = container_of(client, struct vhost_dev, client); - ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK; + struct vhost_dev *dev = container_of(listener, struct vhost_dev, + memory_listener); + target_phys_addr_t start_addr = section->offset_within_address_space; + ram_addr_t size = section->size; + bool log_dirty = memory_region_is_logging(section->mr); int s = offsetof(struct vhost_memory, regions) + (dev->mem->nregions + 1) * sizeof dev->mem->regions[0]; uint64_t log_size; int r; + void *ram; + + if (!memory_region_is_ram(section->mr)) { + return; + } dev->mem = g_realloc(dev->mem, s); if (log_dirty) { - flags = IO_MEM_UNASSIGNED; + add = false; } assert(size); /* Optimize no-change case. At least cirrus_vga does this a lot at this time. */ - if (flags == IO_MEM_RAM) { - if (!vhost_dev_cmp_memory(dev, start_addr, size, - (uintptr_t)qemu_get_ram_ptr(phys_offset))) { + ram = memory_region_get_ram_ptr(section->mr); + if (add) { + if (!vhost_dev_cmp_memory(dev, start_addr, size, (uintptr_t)ram)) { /* Region exists with same address. Nothing to do. */ return; } @@ -371,10 +392,9 @@ static void vhost_client_set_memory(CPUPhysMemoryClient *client, } vhost_dev_unassign_memory(dev, start_addr, size); - if (flags == IO_MEM_RAM) { + if (add) { /* Add given mapping, merging adjacent regions if any */ - vhost_dev_assign_memory(dev, start_addr, size, - (uintptr_t)qemu_get_ram_ptr(phys_offset)); + vhost_dev_assign_memory(dev, start_addr, size, (uintptr_t)ram); } else { /* Remove old mapping for this memory, if any. */ vhost_dev_unassign_memory(dev, start_addr, size); @@ -410,6 +430,38 @@ static void vhost_client_set_memory(CPUPhysMemoryClient *client, } } +static void vhost_region_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + struct vhost_dev *dev = container_of(listener, struct vhost_dev, + memory_listener); + + ++dev->n_mem_sections; + dev->mem_sections = g_renew(MemoryRegionSection, dev->mem_sections, + dev->n_mem_sections); + dev->mem_sections[dev->n_mem_sections - 1] = *section; + vhost_set_memory(listener, section, true); +} + +static void vhost_region_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + struct vhost_dev *dev = container_of(listener, struct vhost_dev, + memory_listener); + int i; + + vhost_set_memory(listener, section, false); + for (i = 0; i < dev->n_mem_sections; ++i) { + if (dev->mem_sections[i].offset_within_address_space + == section->offset_within_address_space) { + --dev->n_mem_sections; + memmove(&dev->mem_sections[i], &dev->mem_sections[i+1], + dev->n_mem_sections - i); + break; + } + } +} + static int vhost_virtqueue_set_addr(struct vhost_dev *dev, struct vhost_virtqueue *vq, unsigned idx, bool enable_log) @@ -467,10 +519,10 @@ err_features: return r; } -static int vhost_client_migration_log(CPUPhysMemoryClient *client, - int enable) +static int vhost_migration_log(MemoryListener *listener, int enable) { - struct vhost_dev *dev = container_of(client, struct vhost_dev, client); + struct vhost_dev *dev = container_of(listener, struct vhost_dev, + memory_listener); int r; if (!!enable == dev->log_enabled) { return 0; @@ -500,6 +552,38 @@ static int vhost_client_migration_log(CPUPhysMemoryClient *client, return 0; } +static void vhost_log_global_start(MemoryListener *listener) +{ + int r; + + r = vhost_migration_log(listener, true); + if (r < 0) { + abort(); + } +} + +static void vhost_log_global_stop(MemoryListener *listener) +{ + int r; + + r = vhost_migration_log(listener, false); + if (r < 0) { + abort(); + } +} + +static void vhost_log_start(MemoryListener *listener, + MemoryRegionSection *section) +{ + /* FIXME: implement */ +} + +static void vhost_log_stop(MemoryListener *listener, + MemoryRegionSection *section) +{ + /* FIXME: implement */ +} + static int vhost_virtqueue_init(struct vhost_dev *dev, struct VirtIODevice *vdev, struct vhost_virtqueue *vq, @@ -645,17 +729,23 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force) } hdev->features = features; - hdev->client.set_memory = vhost_client_set_memory; - hdev->client.sync_dirty_bitmap = vhost_client_sync_dirty_bitmap; - hdev->client.migration_log = vhost_client_migration_log; - hdev->client.log_start = NULL; - hdev->client.log_stop = NULL; + hdev->memory_listener = (MemoryListener) { + .region_add = vhost_region_add, + .region_del = vhost_region_del, + .log_start = vhost_log_start, + .log_stop = vhost_log_stop, + .log_sync = vhost_log_sync, + .log_global_start = vhost_log_global_start, + .log_global_stop = vhost_log_global_stop, + }; hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions)); + hdev->n_mem_sections = 0; + hdev->mem_sections = NULL; hdev->log = NULL; hdev->log_size = 0; hdev->log_enabled = false; hdev->started = false; - cpu_register_phys_memory_client(&hdev->client); + memory_listener_register(&hdev->memory_listener); hdev->force = force; return 0; fail: @@ -666,8 +756,9 @@ fail: void vhost_dev_cleanup(struct vhost_dev *hdev) { - cpu_unregister_phys_memory_client(&hdev->client); + memory_listener_unregister(&hdev->memory_listener); g_free(hdev->mem); + g_free(hdev->mem_sections); close(hdev->control); } @@ -808,8 +899,10 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) hdev->vqs + i, i); } - vhost_client_sync_dirty_bitmap(&hdev->client, 0, - (target_phys_addr_t)~0x0ull); + for (i = 0; i < hdev->n_mem_sections; ++i) { + vhost_sync_dirty_bitmap(hdev, &hdev->mem_sections[i], + 0, (target_phys_addr_t)~0x0ull); + } r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, false); if (r < 0) { fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r); diff --git a/hw/vhost.h b/hw/vhost.h index c9452f073297f96725635d1cf5fa244e56a3a417..80e64df860b7bc37b0cd9029e6c1177eb1e1eb6a 100644 --- a/hw/vhost.h +++ b/hw/vhost.h @@ -3,6 +3,7 @@ #include "hw/hw.h" #include "hw/virtio.h" +#include "memory.h" /* Generic structures common for any vhost based device. */ struct vhost_virtqueue { @@ -26,9 +27,11 @@ typedef unsigned long vhost_log_chunk_t; struct vhost_memory; struct vhost_dev { - CPUPhysMemoryClient client; + MemoryListener memory_listener; int control; struct vhost_memory *mem; + int n_mem_sections; + MemoryRegionSection *mem_sections; struct vhost_virtqueue *vqs; int nvqs; unsigned long long features; diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index e24a2bf1f36e74722e1f07f65ad8560cc9900354..ce9d2c9759be9a5e9c1572d9077496048e8fd831 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -21,6 +21,7 @@ #include "balloon.h" #include "virtio-balloon.h" #include "kvm.h" +#include "exec-memory.h" #if defined(__linux__) #include @@ -70,6 +71,7 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) { VirtIOBalloon *s = to_virtio_balloon(vdev); VirtQueueElement elem; + MemoryRegionSection section; while (virtqueue_pop(vq, &elem)) { size_t offset = 0; @@ -82,13 +84,16 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) pa = (ram_addr_t)ldl_p(&pfn) << VIRTIO_BALLOON_PFN_SHIFT; offset += 4; - addr = cpu_get_physical_page_desc(pa); - if ((addr & ~TARGET_PAGE_MASK) != IO_MEM_RAM) + /* FIXME: remove get_system_memory(), but how? */ + section = memory_region_find(get_system_memory(), pa, 1); + if (!section.size || !memory_region_is_ram(section.mr)) continue; - /* Using qemu_get_ram_ptr is bending the rules a bit, but + /* Using memory_region_get_ram_ptr is bending the rules a bit, but should be OK because we only want a single page. */ - balloon_page(qemu_get_ram_ptr(addr), !!(vq == s->dvq)); + addr = section.offset_within_region; + balloon_page(memory_region_get_ram_ptr(section.mr) + addr, + !!(vq == s->dvq)); } virtqueue_push(vq, &elem, offset); diff --git a/hw/xen.h b/hw/xen.h index f9f66e83ef556212e7dc10a0db1d664ad4cbcb01..b46879c6f733ed06886de56ce34b4f7a8cd2266d 100644 --- a/hw/xen.h +++ b/hw/xen.h @@ -49,6 +49,9 @@ void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, struct MemoryRegion *mr); #endif +struct MemoryRegion; +void xen_register_framebuffer(struct MemoryRegion *mr); + #if defined(CONFIG_XEN) && CONFIG_XEN_CTRL_INTERFACE_VERSION < 400 # define HVM_MAX_VCPUS 32 #endif diff --git a/kvm-all.c b/kvm-all.c index ac048bce509d9ca3851edfc1fafa4e324d72a936..3174f42a371bed602594f149eb694d6da01cee45 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -27,6 +27,7 @@ #include "gdbstub.h" #include "kvm.h" #include "bswap.h" +#include "memory.h" /* This check must be after config-host.h is included */ #ifdef CONFIG_EVENTFD @@ -50,7 +51,7 @@ typedef struct KVMSlot { target_phys_addr_t start_addr; ram_addr_t memory_size; - ram_addr_t phys_offset; + void *ram; int slot; int flags; } KVMSlot; @@ -146,17 +147,16 @@ static KVMSlot *kvm_lookup_overlapping_slot(KVMState *s, return found; } -int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr, - target_phys_addr_t *phys_addr) +int kvm_physical_memory_addr_from_host(KVMState *s, void *ram, + target_phys_addr_t *phys_addr) { int i; for (i = 0; i < ARRAY_SIZE(s->slots); i++) { KVMSlot *mem = &s->slots[i]; - if (ram_addr >= mem->phys_offset && - ram_addr < mem->phys_offset + mem->memory_size) { - *phys_addr = mem->start_addr + (ram_addr - mem->phys_offset); + if (ram >= mem->ram && ram < mem->ram + mem->memory_size) { + *phys_addr = mem->start_addr + (ram - mem->ram); return 1; } } @@ -171,7 +171,7 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot) mem.slot = slot->slot; mem.guest_phys_addr = slot->start_addr; mem.memory_size = slot->memory_size; - mem.userspace_addr = (unsigned long)qemu_safe_ram_ptr(slot->phys_offset); + mem.userspace_addr = (unsigned long)slot->ram; mem.flags = slot->flags; if (s->migration_log) { mem.flags |= KVM_MEM_LOG_DIRTY_PAGES; @@ -290,16 +290,28 @@ static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr, return kvm_slot_dirty_pages_log_change(mem, log_dirty); } -static int kvm_log_start(CPUPhysMemoryClient *client, - target_phys_addr_t phys_addr, ram_addr_t size) +static void kvm_log_start(MemoryListener *listener, + MemoryRegionSection *section) { - return kvm_dirty_pages_log_change(phys_addr, size, true); + int r; + + r = kvm_dirty_pages_log_change(section->offset_within_address_space, + section->size, true); + if (r < 0) { + abort(); + } } -static int kvm_log_stop(CPUPhysMemoryClient *client, - target_phys_addr_t phys_addr, ram_addr_t size) +static void kvm_log_stop(MemoryListener *listener, + MemoryRegionSection *section) { - return kvm_dirty_pages_log_change(phys_addr, size, false); + int r; + + r = kvm_dirty_pages_log_change(section->offset_within_address_space, + section->size, false); + if (r < 0) { + abort(); + } } static int kvm_set_migration_log(int enable) @@ -328,16 +340,12 @@ static int kvm_set_migration_log(int enable) } /* get kvm's dirty pages bitmap and update qemu's */ -static int kvm_get_dirty_pages_log_range(unsigned long start_addr, - unsigned long *bitmap, - unsigned long offset, - unsigned long mem_size) +static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section, + unsigned long *bitmap) { unsigned int i, j; unsigned long page_number, addr, addr1, c; - ram_addr_t ram_addr; - unsigned int len = ((mem_size / TARGET_PAGE_SIZE) + HOST_LONG_BITS - 1) / - HOST_LONG_BITS; + unsigned int len = ((section->size / TARGET_PAGE_SIZE) + HOST_LONG_BITS - 1) / HOST_LONG_BITS; /* * bitmap-traveling is faster than memory-traveling (for addr...) @@ -351,9 +359,8 @@ static int kvm_get_dirty_pages_log_range(unsigned long start_addr, c &= ~(1ul << j); page_number = i * HOST_LONG_BITS + j; addr1 = page_number * TARGET_PAGE_SIZE; - addr = offset + addr1; - ram_addr = cpu_get_physical_page_desc(addr); - cpu_physical_memory_set_dirty(ram_addr); + addr = section->offset_within_region + addr1; + memory_region_set_dirty(section->mr, addr); } while (c != 0); } } @@ -370,14 +377,15 @@ static int kvm_get_dirty_pages_log_range(unsigned long start_addr, * @start_add: start of logged region. * @end_addr: end of logged region. */ -static int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, - target_phys_addr_t end_addr) +static int kvm_physical_sync_dirty_bitmap(MemoryRegionSection *section) { KVMState *s = kvm_state; unsigned long size, allocated_size = 0; KVMDirtyLog d; KVMSlot *mem; int ret = 0; + target_phys_addr_t start_addr = section->offset_within_address_space; + target_phys_addr_t end_addr = start_addr + section->size; d.dirty_bitmap = NULL; while (start_addr < end_addr) { @@ -416,8 +424,7 @@ static int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, break; } - kvm_get_dirty_pages_log_range(mem->start_addr, d.dirty_bitmap, - mem->start_addr, mem->memory_size); + kvm_get_dirty_pages_log_range(section, d.dirty_bitmap); start_addr = mem->start_addr + mem->memory_size; } g_free(d.dirty_bitmap); @@ -520,21 +527,27 @@ kvm_check_extension_list(KVMState *s, const KVMCapabilityInfo *list) return NULL; } -static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, - ram_addr_t phys_offset, bool log_dirty) +static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) { KVMState *s = kvm_state; - ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK; KVMSlot *mem, old; int err; + MemoryRegion *mr = section->mr; + bool log_dirty = memory_region_is_logging(mr); + target_phys_addr_t start_addr = section->offset_within_address_space; + ram_addr_t size = section->size; + void *ram = NULL; /* kvm works in page size chunks, but the function may be called with sub-page size and unaligned start address. */ size = TARGET_PAGE_ALIGN(size); start_addr = TARGET_PAGE_ALIGN(start_addr); - /* KVM does not support read-only slots */ - phys_offset &= ~IO_MEM_ROM; + if (!memory_region_is_ram(mr)) { + return; + } + + ram = memory_region_get_ram_ptr(mr) + section->offset_within_region; while (1) { mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size); @@ -542,9 +555,9 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, break; } - if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr && + if (add && start_addr >= mem->start_addr && (start_addr + size <= mem->start_addr + mem->memory_size) && - (phys_offset - start_addr == mem->phys_offset - mem->start_addr)) { + (ram - start_addr == mem->ram - mem->start_addr)) { /* The new slot fits into the existing one and comes with * identical parameters - update flags and done. */ kvm_slot_dirty_pages_log_change(mem, log_dirty); @@ -571,12 +584,11 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, * slot comes around later, we will fail (not seen in practice so far) * - and actually require a recent KVM version. */ if (s->broken_set_mem_region && - old.start_addr == start_addr && old.memory_size < size && - flags < IO_MEM_UNASSIGNED) { + old.start_addr == start_addr && old.memory_size < size && add) { mem = kvm_alloc_slot(s); mem->memory_size = old.memory_size; mem->start_addr = old.start_addr; - mem->phys_offset = old.phys_offset; + mem->ram = old.ram; mem->flags = kvm_mem_flags(s, log_dirty); err = kvm_set_user_memory_region(s, mem); @@ -587,7 +599,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, } start_addr += old.memory_size; - phys_offset += old.memory_size; + ram += old.memory_size; size -= old.memory_size; continue; } @@ -597,7 +609,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, mem = kvm_alloc_slot(s); mem->memory_size = start_addr - old.start_addr; mem->start_addr = old.start_addr; - mem->phys_offset = old.phys_offset; + mem->ram = old.ram; mem->flags = kvm_mem_flags(s, log_dirty); err = kvm_set_user_memory_region(s, mem); @@ -621,7 +633,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, mem->start_addr = start_addr + size; size_delta = mem->start_addr - old.start_addr; mem->memory_size = old.memory_size - size_delta; - mem->phys_offset = old.phys_offset + size_delta; + mem->ram = old.ram + size_delta; mem->flags = kvm_mem_flags(s, log_dirty); err = kvm_set_user_memory_region(s, mem); @@ -637,14 +649,13 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, if (!size) { return; } - /* KVM does not need to know about this memory */ - if (flags >= IO_MEM_UNASSIGNED) { + if (!add) { return; } mem = kvm_alloc_slot(s); mem->memory_size = size; mem->start_addr = start_addr; - mem->phys_offset = phys_offset; + mem->ram = ram; mem->flags = kvm_mem_flags(s, log_dirty); err = kvm_set_user_memory_region(s, mem); @@ -655,33 +666,53 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, } } -static void kvm_client_set_memory(struct CPUPhysMemoryClient *client, - target_phys_addr_t start_addr, - ram_addr_t size, ram_addr_t phys_offset, - bool log_dirty) +static void kvm_region_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + kvm_set_phys_mem(section, true); +} + +static void kvm_region_del(MemoryListener *listener, + MemoryRegionSection *section) { - kvm_set_phys_mem(start_addr, size, phys_offset, log_dirty); + kvm_set_phys_mem(section, false); +} + +static void kvm_log_sync(MemoryListener *listener, + MemoryRegionSection *section) +{ + int r; + + r = kvm_physical_sync_dirty_bitmap(section); + if (r < 0) { + abort(); + } } -static int kvm_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client, - target_phys_addr_t start_addr, - target_phys_addr_t end_addr) +static void kvm_log_global_start(struct MemoryListener *listener) { - return kvm_physical_sync_dirty_bitmap(start_addr, end_addr); + int r; + + r = kvm_set_migration_log(1); + assert(r >= 0); } -static int kvm_client_migration_log(struct CPUPhysMemoryClient *client, - int enable) +static void kvm_log_global_stop(struct MemoryListener *listener) { - return kvm_set_migration_log(enable); + int r; + + r = kvm_set_migration_log(0); + assert(r >= 0); } -static CPUPhysMemoryClient kvm_cpu_phys_memory_client = { - .set_memory = kvm_client_set_memory, - .sync_dirty_bitmap = kvm_client_sync_dirty_bitmap, - .migration_log = kvm_client_migration_log, +static MemoryListener kvm_memory_listener = { + .region_add = kvm_region_add, + .region_del = kvm_region_del, .log_start = kvm_log_start, .log_stop = kvm_log_stop, + .log_sync = kvm_log_sync, + .log_global_start = kvm_log_global_start, + .log_global_stop = kvm_log_global_stop, }; static void kvm_handle_interrupt(CPUState *env, int mask) @@ -789,7 +820,7 @@ int kvm_init(void) } kvm_state = s; - cpu_register_phys_memory_client(&kvm_cpu_phys_memory_client); + memory_listener_register(&kvm_memory_listener); s->many_ioeventfds = kvm_check_many_ioeventfds(); diff --git a/kvm.h b/kvm.h index 243b063f92d9c4824000b05d8895f659ed999a4d..c1de81a11c32693a24b01172f6f13509e0e8ff9b 100644 --- a/kvm.h +++ b/kvm.h @@ -188,8 +188,8 @@ static inline void cpu_synchronize_post_init(CPUState *env) #if !defined(CONFIG_USER_ONLY) -int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr, - target_phys_addr_t *phys_addr); +int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr, + target_phys_addr_t *phys_addr); #endif #endif diff --git a/memory.c b/memory.c index a7e615ad15f018fec2dbc01157801c9237d77153..a90eefd8d1e5b63f2f004eecf525a56085ca9d0b 100644 --- a/memory.c +++ b/memory.c @@ -23,6 +23,10 @@ unsigned memory_region_transaction_depth = 0; static bool memory_region_update_pending = false; +static bool global_dirty_log = false; + +static QLIST_HEAD(, MemoryListener) memory_listeners + = QLIST_HEAD_INITIALIZER(memory_listeners); typedef struct AddrRange AddrRange; @@ -334,11 +338,6 @@ static void as_memory_range_add(AddressSpace *as, FlatRange *fr) static void as_memory_range_del(AddressSpace *as, FlatRange *fr) { - if (fr->dirty_log_mask) { - Int128 end = addrrange_end(fr->addr); - cpu_physical_sync_dirty_bitmap(int128_get64(fr->addr.start), - int128_get64(end)); - } cpu_register_physical_memory(int128_get64(fr->addr.start), int128_get64(fr->addr.size), IO_MEM_UNASSIGNED); @@ -346,14 +345,10 @@ static void as_memory_range_del(AddressSpace *as, FlatRange *fr) static void as_memory_log_start(AddressSpace *as, FlatRange *fr) { - cpu_physical_log_start(int128_get64(fr->addr.start), - int128_get64(fr->addr.size)); } static void as_memory_log_stop(AddressSpace *as, FlatRange *fr) { - cpu_physical_log_stop(int128_get64(fr->addr.start), - int128_get64(fr->addr.size)); } static void as_memory_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd *fd) @@ -515,6 +510,20 @@ static AddressSpace address_space_io = { .ops = &address_space_ops_io, }; +static AddressSpace *memory_region_to_address_space(MemoryRegion *mr) +{ + while (mr->parent) { + mr = mr->parent; + } + if (mr == address_space_memory.root) { + return &address_space_memory; + } + if (mr == address_space_io.root) { + return &address_space_io; + } + abort(); +} + /* Render a memory region into the global view. Ranges in @view obscure * ranges in @mr. */ @@ -683,6 +692,32 @@ static void address_space_update_ioeventfds(AddressSpace *as) as->ioeventfd_nb = ioeventfd_nb; } +typedef void ListenerCallback(MemoryListener *listener, + MemoryRegionSection *mrs); + +/* Want "void (&MemoryListener::*callback)(const MemoryRegionSection& s)" */ +static void memory_listener_update_region(FlatRange *fr, AddressSpace *as, + size_t callback_offset) +{ + MemoryRegionSection section = { + .mr = fr->mr, + .address_space = as->root, + .offset_within_region = fr->offset_in_region, + .size = int128_get64(fr->addr.size), + .offset_within_address_space = int128_get64(fr->addr.start), + }; + MemoryListener *listener; + + QLIST_FOREACH(listener, &memory_listeners, link) { + ListenerCallback *callback + = *(ListenerCallback **)((void *)listener + callback_offset); + callback(listener, §ion); + } +} + +#define MEMORY_LISTENER_UPDATE_REGION(fr, as, callback) \ + memory_listener_update_region(fr, as, offsetof(MemoryListener, callback)) + static void address_space_update_topology_pass(AddressSpace *as, FlatView old_view, FlatView new_view, @@ -715,6 +750,7 @@ static void address_space_update_topology_pass(AddressSpace *as, /* In old, but (not in new, or in new but attributes changed). */ if (!adding) { + MEMORY_LISTENER_UPDATE_REGION(frold, as, region_del); as->ops->range_del(as, frold); } @@ -724,9 +760,11 @@ static void address_space_update_topology_pass(AddressSpace *as, if (adding) { if (frold->dirty_log_mask && !frnew->dirty_log_mask) { + MEMORY_LISTENER_UPDATE_REGION(frnew, as, log_stop); as->ops->log_stop(as, frnew); } else if (frnew->dirty_log_mask && !frold->dirty_log_mask) { as->ops->log_start(as, frnew); + MEMORY_LISTENER_UPDATE_REGION(frnew, as, log_start); } } @@ -737,6 +775,7 @@ static void address_space_update_topology_pass(AddressSpace *as, if (adding) { as->ops->range_add(as, frnew); + MEMORY_LISTENER_UPDATE_REGION(frnew, as, region_add); } ++inew; @@ -832,6 +871,7 @@ void memory_region_init(MemoryRegion *mr, mr->offset = 0; mr->enabled = true; mr->terminates = false; + mr->ram = false; mr->readable = true; mr->readonly = false; mr->destructor = memory_region_destructor_none; @@ -998,6 +1038,7 @@ void memory_region_init_ram(MemoryRegion *mr, uint64_t size) { memory_region_init(mr, name, size); + mr->ram = true; mr->terminates = true; mr->destructor = memory_region_destructor_ram; mr->ram_addr = qemu_ram_alloc(dev, name, size, mr); @@ -1011,6 +1052,7 @@ void memory_region_init_ram_ptr(MemoryRegion *mr, void *ptr) { memory_region_init(mr, name, size); + mr->ram = true; mr->terminates = true; mr->destructor = memory_region_destructor_ram_from_ptr; mr->ram_addr = qemu_ram_alloc_from_ptr(dev, name, size, ptr, mr); @@ -1066,6 +1108,21 @@ uint64_t memory_region_size(MemoryRegion *mr) return int128_get64(mr->size); } +bool memory_region_is_ram(MemoryRegion *mr) +{ + return mr->ram; +} + +bool memory_region_is_logging(MemoryRegion *mr) +{ + return mr->dirty_log_mask; +} + +bool memory_region_is_rom(MemoryRegion *mr) +{ + return mr->ram && mr->readonly; +} + void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset) { mr->offset = offset; @@ -1098,8 +1155,7 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr) FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) { if (fr->mr == mr) { - cpu_physical_sync_dirty_bitmap(int128_get64(fr->addr.start), - int128_get64(addrrange_end(fr->addr))); + MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory, log_sync); } } } @@ -1368,6 +1424,121 @@ void memory_region_set_alias_offset(MemoryRegion *mr, target_phys_addr_t offset) memory_region_update_topology(mr); } +ram_addr_t memory_region_get_ram_addr(MemoryRegion *mr) +{ + assert(mr->backend_registered); + return mr->ram_addr; +} + +static int cmp_flatrange_addr(const void *addr_, const void *fr_) +{ + const AddrRange *addr = addr_; + const FlatRange *fr = fr_; + + if (int128_le(addrrange_end(*addr), fr->addr.start)) { + return -1; + } else if (int128_ge(addr->start, addrrange_end(fr->addr))) { + return 1; + } + return 0; +} + +static FlatRange *address_space_lookup(AddressSpace *as, AddrRange addr) +{ + return bsearch(&addr, as->current_map.ranges, as->current_map.nr, + sizeof(FlatRange), cmp_flatrange_addr); +} + +MemoryRegionSection memory_region_find(MemoryRegion *address_space, + target_phys_addr_t addr, uint64_t size) +{ + AddressSpace *as = memory_region_to_address_space(address_space); + AddrRange range = addrrange_make(int128_make64(addr), + int128_make64(size)); + FlatRange *fr = address_space_lookup(as, range); + MemoryRegionSection ret = { .mr = NULL, .size = 0 }; + + if (!fr) { + return ret; + } + + while (fr > as->current_map.ranges + && addrrange_intersects(fr[-1].addr, range)) { + --fr; + } + + ret.mr = fr->mr; + range = addrrange_intersection(range, fr->addr); + ret.offset_within_region = fr->offset_in_region; + ret.offset_within_region += int128_get64(int128_sub(range.start, + fr->addr.start)); + ret.size = int128_get64(range.size); + ret.offset_within_address_space = int128_get64(range.start); + return ret; +} + +void memory_global_sync_dirty_bitmap(MemoryRegion *address_space) +{ + AddressSpace *as = memory_region_to_address_space(address_space); + FlatRange *fr; + + FOR_EACH_FLAT_RANGE(fr, &as->current_map) { + MEMORY_LISTENER_UPDATE_REGION(fr, as, log_sync); + } +} + +void memory_global_dirty_log_start(void) +{ + MemoryListener *listener; + + global_dirty_log = true; + QLIST_FOREACH(listener, &memory_listeners, link) { + listener->log_global_start(listener); + } +} + +void memory_global_dirty_log_stop(void) +{ + MemoryListener *listener; + + global_dirty_log = false; + QLIST_FOREACH(listener, &memory_listeners, link) { + listener->log_global_stop(listener); + } +} + +static void listener_add_address_space(MemoryListener *listener, + AddressSpace *as) +{ + FlatRange *fr; + + if (global_dirty_log) { + listener->log_global_start(listener); + } + FOR_EACH_FLAT_RANGE(fr, &as->current_map) { + MemoryRegionSection section = { + .mr = fr->mr, + .address_space = as->root, + .offset_within_region = fr->offset_in_region, + .size = int128_get64(fr->addr.size), + .offset_within_address_space = int128_get64(fr->addr.start), + }; + listener->region_add(listener, §ion); + } +} + +void memory_listener_register(MemoryListener *listener) +{ + QLIST_INSERT_HEAD(&memory_listeners, listener, link); + listener_add_address_space(listener, &address_space_memory); + listener_add_address_space(listener, &address_space_io); +} + +void memory_listener_unregister(MemoryListener *listener) +{ + QLIST_REMOVE(listener, link); +} + void set_system_memory_map(MemoryRegion *mr) { address_space_memory.root = mr; diff --git a/memory.h b/memory.h index fe643ff05bc1db8a510bad858f4443422e1b307f..a82226a752f09ded16d5115e5c11f87892fec9f8 100644 --- a/memory.h +++ b/memory.h @@ -122,6 +122,7 @@ struct MemoryRegion { IORange iorange; bool terminates; bool readable; + bool ram; bool readonly; /* For RAM regions */ bool enabled; MemoryRegion *alias; @@ -147,6 +148,45 @@ struct MemoryRegionPortio { #define PORTIO_END_OF_LIST() { } +typedef struct MemoryRegionSection MemoryRegionSection; + +/** + * MemoryRegionSection: describes a fragment of a #MemoryRegion + * + * @mr: the region, or %NULL if empty + * @address_space: the address space the region is mapped in + * @offset_within_region: the beginning of the section, relative to @mr's start + * @size: the size of the section; will not exceed @mr's boundaries + * @offset_within_address_space: the address of the first byte of the section + * relative to the region's address space + */ +struct MemoryRegionSection { + MemoryRegion *mr; + MemoryRegion *address_space; + target_phys_addr_t offset_within_region; + uint64_t size; + target_phys_addr_t offset_within_address_space; +}; + +typedef struct MemoryListener MemoryListener; + +/** + * MemoryListener: callbacks structure for updates to the physical memory map + * + * Allows a component to adjust to changes in the guest-visible memory map. + * Use with memory_listener_register() and memory_listener_unregister(). + */ +struct MemoryListener { + void (*region_add)(MemoryListener *listener, MemoryRegionSection *section); + void (*region_del)(MemoryListener *listener, MemoryRegionSection *section); + void (*log_start)(MemoryListener *listener, MemoryRegionSection *section); + void (*log_stop)(MemoryListener *listener, MemoryRegionSection *section); + void (*log_sync)(MemoryListener *listener, MemoryRegionSection *section); + void (*log_global_start)(MemoryListener *listener); + void (*log_global_stop)(MemoryListener *listener); + QLIST_ENTRY(MemoryListener) link; +}; + /** * memory_region_init: Initialize a memory region * @@ -266,6 +306,33 @@ void memory_region_destroy(MemoryRegion *mr); */ uint64_t memory_region_size(MemoryRegion *mr); +/** + * memory_region_is_ram: check whether a memory region is random access + * + * Returns %true is a memory region is random access. + * + * @mr: the memory region being queried + */ +bool memory_region_is_ram(MemoryRegion *mr); + +/** + * memory_region_is_logging: return whether a memory region is logging writes + * + * Returns %true if the memory region is logging writes + * + * @mr: the memory region being queried + */ +bool memory_region_is_logging(MemoryRegion *mr); + +/** + * memory_region_is_rom: check whether a memory region is ROM + * + * Returns %true is a memory region is read-only memory. + * + * @mr: the memory region being queried + */ +bool memory_region_is_rom(MemoryRegion *mr); + /** * memory_region_get_ram_ptr: Get a pointer into a RAM memory region. * @@ -491,6 +558,16 @@ void memory_region_add_subregion_overlap(MemoryRegion *mr, target_phys_addr_t offset, MemoryRegion *subregion, unsigned priority); + +/** + * memory_region_get_ram_addr: Get the ram address associated with a memory + * region + * + * DO NOT USE THIS FUCNTION. This is a temporary workaround while the Xen + * code is being reworked. + */ +ram_addr_t memory_region_get_ram_addr(MemoryRegion *mr); + /** * memory_region_del_subregion: Remove a subregion. * @@ -540,6 +617,37 @@ void memory_region_set_address(MemoryRegion *mr, target_phys_addr_t addr); void memory_region_set_alias_offset(MemoryRegion *mr, target_phys_addr_t offset); +/** + * memory_region_find: locate a MemoryRegion in an address space + * + * Locates the first #MemoryRegion within an address space given by + * @address_space that overlaps the range given by @addr and @size. + * + * Returns a #MemoryRegionSection that describes a contiguous overlap. + * It will have the following characteristics: + * .@offset_within_address_space >= @addr + * .@offset_within_address_space + .@size <= @addr + @size + * .@size = 0 iff no overlap was found + * .@mr is non-%NULL iff an overlap was found + * + * @address_space: a top-level (i.e. parentless) region that contains + * the region to be found + * @addr: start of the area within @address_space to be searched + * @size: size of the area to be searched + */ +MemoryRegionSection memory_region_find(MemoryRegion *address_space, + target_phys_addr_t addr, uint64_t size); + + +/** + * memory_global_sync_dirty_bitmap: synchronize the dirty log for all memory + * + * Synchronizes the dirty page log for an entire address space. + * @address_space: a top-level (i.e. parentless) region that contains the + * memory being synchronized + */ +void memory_global_sync_dirty_bitmap(MemoryRegion *address_space); + /** * memory_region_transaction_begin: Start a transaction. * @@ -554,6 +662,32 @@ void memory_region_transaction_begin(void); */ void memory_region_transaction_commit(void); +/** + * memory_listener_register: register callbacks to be called when memory + * sections are mapped or unmapped into an address + * space + * + * @listener: an object containing the callbacks to be called + */ +void memory_listener_register(MemoryListener *listener); + +/** + * memory_listener_unregister: undo the effect of memory_listener_register() + * + * @listener: an object containing the callbacks to be removed + */ +void memory_listener_unregister(MemoryListener *listener); + +/** + * memory_global_dirty_log_start: begin dirty logging for all regions + */ +void memory_global_dirty_log_start(void); + +/** + * memory_global_dirty_log_stop: begin dirty logging for all regions + */ +void memory_global_dirty_log_stop(void); + void mtree_info(fprintf_function mon_printf, void *f); #endif diff --git a/target-i386/kvm.c b/target-i386/kvm.c index d20685290490a9d5f37171c6b6104291ce3a1194..04e65c5ea1659ff49e16c331e719740b296a6868 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -253,8 +253,7 @@ int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr) if ((env->mcg_cap & MCG_SER_P) && addr && (code == BUS_MCEERR_AR || code == BUS_MCEERR_AO)) { if (qemu_ram_addr_from_host(addr, &ram_addr) || - !kvm_physical_memory_addr_from_ram(env->kvm_state, ram_addr, - &paddr)) { + !kvm_physical_memory_addr_from_host(env->kvm_state, addr, &paddr)) { fprintf(stderr, "Hardware memory error for memory used by " "QEMU itself instead of guest system!\n"); /* Hope we are lucky for AO MCE */ @@ -286,8 +285,8 @@ int kvm_arch_on_sigbus(int code, void *addr) /* Hope we are lucky for AO MCE */ if (qemu_ram_addr_from_host(addr, &ram_addr) || - !kvm_physical_memory_addr_from_ram(first_cpu->kvm_state, ram_addr, - &paddr)) { + !kvm_physical_memory_addr_from_host(first_cpu->kvm_state, addr, + &paddr)) { fprintf(stderr, "Hardware memory error for memory used by " "QEMU itself instead of guest system!: %p\n", addr); return 0; diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c index 8cdc224ae3fe1674cc21ba715aa4f611810f6aef..bdff1c32543781e1b6bee6df253e08f695ffc91e 100644 --- a/target-sparc/mmu_helper.c +++ b/target-sparc/mmu_helper.c @@ -19,6 +19,7 @@ #include "cpu.h" #include "trace.h" +#include "exec-memory.h" /* Sparc MMU emulation */ @@ -839,13 +840,15 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { target_phys_addr_t phys_addr; int mmu_idx = cpu_mmu_index(env); + MemoryRegionSection section; if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) { if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) { return -1; } } - if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) { + section = memory_region_find(get_system_memory(), phys_addr, 1); + if (!section.size) { return -1; } return phys_addr; diff --git a/trace-events b/trace-events index 2918398ff4c2b2d2e59ed922f10bf7fa586ba160..c18435bbe1a82ed3ee517a4e376bfffef83f469d 100644 --- a/trace-events +++ b/trace-events @@ -462,7 +462,7 @@ mipsnet_irq(uint32_t isr, uint32_t intctl) "set irq to %d (%02x)" # xen-all.c xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: %#lx, size %#lx" -xen_client_set_memory(uint64_t start_addr, unsigned long size, unsigned long phys_offset, bool log_dirty) "%#"PRIx64" size %#lx, offset %#lx, log_dirty %i" +xen_client_set_memory(uint64_t start_addr, unsigned long size, bool log_dirty) "%#"PRIx64" size %#lx, log_dirty %i" # xen-mapcache.c xen_map_cache(uint64_t phys_addr) "want %#"PRIx64 diff --git a/xen-all.c b/xen-all.c index bd8988950255d45b2d3f519b3b0bda2ba28ba60c..dc232651e745e3bc4177396a7451dc462e09e481 100644 --- a/xen-all.c +++ b/xen-all.c @@ -33,6 +33,7 @@ #endif static MemoryRegion ram_memory, ram_640k, ram_lo, ram_hi; +static MemoryRegion *framebuffer; /* Compatibility with older version */ #if __XEN_LATEST_INTERFACE_VERSION__ < 0x0003020a @@ -62,6 +63,7 @@ static inline ioreq_t *xen_vcpu_ioreq(shared_iopage_t *shared_page, int vcpu) typedef struct XenPhysmap { target_phys_addr_t start_addr; ram_addr_t size; + MemoryRegion *mr; target_phys_addr_t phys_offset; QLIST_ENTRY(XenPhysmap) list; @@ -79,8 +81,9 @@ typedef struct XenIOState { int send_vcpu; struct xs_handle *xenstore; - CPUPhysMemoryClient client; + MemoryListener memory_listener; QLIST_HEAD(, XenPhysmap) physmap; + target_phys_addr_t free_phys_offset; const XenPhysmap *log_for_dirtybit; Notifier exit; @@ -225,13 +228,14 @@ static XenPhysmap *get_physmapping(XenIOState *state, static int xen_add_to_physmap(XenIOState *state, target_phys_addr_t start_addr, ram_addr_t size, - target_phys_addr_t phys_offset) + MemoryRegion *mr, + target_phys_addr_t offset_within_region) { unsigned long i = 0; int rc = 0; XenPhysmap *physmap = NULL; target_phys_addr_t pfn, start_gpfn; - RAMBlock *block; + target_phys_addr_t phys_offset = memory_region_get_ram_addr(mr); if (get_physmapping(state, start_addr, size)) { return 0; @@ -244,17 +248,13 @@ static int xen_add_to_physmap(XenIOState *state, * the linear framebuffer to be that region. * Avoid tracking any regions that is not videoram and avoid tracking * the legacy vga region. */ - QLIST_FOREACH(block, &ram_list.blocks, next) { - if (!strcmp(block->idstr, "vga.vram") && block->offset == phys_offset - && start_addr > 0xbffff) { - goto go_physmap; - } + if (mr == framebuffer && start_addr > 0xbffff) { + goto go_physmap; } return -1; go_physmap: - DPRINTF("mapping vram to %llx - %llx, from %llx\n", - start_addr, start_addr + size, phys_offset); + DPRINTF("mapping vram to %llx - %llx\n", start_addr, start_addr + size); pfn = phys_offset >> TARGET_PAGE_BITS; start_gpfn = start_addr >> TARGET_PAGE_BITS; @@ -333,7 +333,8 @@ static int xen_remove_from_physmap(XenIOState *state, static int xen_add_to_physmap(XenIOState *state, target_phys_addr_t start_addr, ram_addr_t size, - target_phys_addr_t phys_offset) + MemoryRegion *mr, + target_phys_addr_t offset_within_region) { return -ENOSYS; } @@ -346,49 +347,62 @@ static int xen_remove_from_physmap(XenIOState *state, } #endif -static void xen_client_set_memory(struct CPUPhysMemoryClient *client, - target_phys_addr_t start_addr, - ram_addr_t size, - ram_addr_t phys_offset, - bool log_dirty) +static void xen_set_memory(struct MemoryListener *listener, + MemoryRegionSection *section, + bool add) { - XenIOState *state = container_of(client, XenIOState, client); - ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK; + XenIOState *state = container_of(listener, XenIOState, memory_listener); + target_phys_addr_t start_addr = section->offset_within_address_space; + ram_addr_t size = section->size; + bool log_dirty = memory_region_is_logging(section->mr); hvmmem_type_t mem_type; - if (!(start_addr != phys_offset - && ( (log_dirty && flags < IO_MEM_UNASSIGNED) - || (!log_dirty && flags == IO_MEM_UNASSIGNED)))) { + if (!memory_region_is_ram(section->mr)) { + return; + } + + if (!(section->mr != &ram_memory + && ( (log_dirty && add) || (!log_dirty && !add)))) { return; } - trace_xen_client_set_memory(start_addr, size, phys_offset, log_dirty); + trace_xen_client_set_memory(start_addr, size, log_dirty); start_addr &= TARGET_PAGE_MASK; size = TARGET_PAGE_ALIGN(size); - phys_offset &= TARGET_PAGE_MASK; - - switch (flags) { - case IO_MEM_RAM: - xen_add_to_physmap(state, start_addr, size, phys_offset); - break; - case IO_MEM_ROM: - mem_type = HVMMEM_ram_ro; - if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type, - start_addr >> TARGET_PAGE_BITS, - size >> TARGET_PAGE_BITS)) { - DPRINTF("xc_hvm_set_mem_type error, addr: "TARGET_FMT_plx"\n", - start_addr); + + if (add) { + if (!memory_region_is_rom(section->mr)) { + xen_add_to_physmap(state, start_addr, size, + section->mr, section->offset_within_region); + } else { + mem_type = HVMMEM_ram_ro; + if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type, + start_addr >> TARGET_PAGE_BITS, + size >> TARGET_PAGE_BITS)) { + DPRINTF("xc_hvm_set_mem_type error, addr: "TARGET_FMT_plx"\n", + start_addr); + } } - break; - case IO_MEM_UNASSIGNED: + } else { if (xen_remove_from_physmap(state, start_addr, size) < 0) { DPRINTF("physmapping does not exist at "TARGET_FMT_plx"\n", start_addr); } - break; } } +static void xen_region_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + xen_set_memory(listener, section, true); +} + +static void xen_region_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + xen_set_memory(listener, section, false); +} + static int xen_sync_dirty_bitmap(XenIOState *state, target_phys_addr_t start_addr, ram_addr_t size) @@ -432,43 +446,54 @@ static int xen_sync_dirty_bitmap(XenIOState *state, return 0; } -static int xen_log_start(CPUPhysMemoryClient *client, target_phys_addr_t phys_addr, ram_addr_t size) +static void xen_log_start(MemoryListener *listener, + MemoryRegionSection *section) { - XenIOState *state = container_of(client, XenIOState, client); + XenIOState *state = container_of(listener, XenIOState, memory_listener); + int r; - return xen_sync_dirty_bitmap(state, phys_addr, size); + r = xen_sync_dirty_bitmap(state, section->offset_within_address_space, + section->size); + assert(r >= 0); } -static int xen_log_stop(CPUPhysMemoryClient *client, target_phys_addr_t phys_addr, ram_addr_t size) +static void xen_log_stop(MemoryListener *listener, MemoryRegionSection *section) { - XenIOState *state = container_of(client, XenIOState, client); + XenIOState *state = container_of(listener, XenIOState, memory_listener); + int r; state->log_for_dirtybit = NULL; /* Disable dirty bit tracking */ - return xc_hvm_track_dirty_vram(xen_xc, xen_domid, 0, 0, NULL); + r = xc_hvm_track_dirty_vram(xen_xc, xen_domid, 0, 0, NULL); + assert(r >= 0); } -static int xen_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client, - target_phys_addr_t start_addr, - target_phys_addr_t end_addr) +static void xen_log_sync(MemoryListener *listener, MemoryRegionSection *section) { - XenIOState *state = container_of(client, XenIOState, client); + XenIOState *state = container_of(listener, XenIOState, memory_listener); + int r; - return xen_sync_dirty_bitmap(state, start_addr, end_addr - start_addr); + r = xen_sync_dirty_bitmap(state, section->offset_within_address_space, + section->size); + assert(r >= 0); } -static int xen_client_migration_log(struct CPUPhysMemoryClient *client, - int enable) +static void xen_log_global_start(MemoryListener *listener) +{ +} + +static void xen_log_global_stop(MemoryListener *listener) { - return 0; } -static CPUPhysMemoryClient xen_cpu_phys_memory_client = { - .set_memory = xen_client_set_memory, - .sync_dirty_bitmap = xen_client_sync_dirty_bitmap, - .migration_log = xen_client_migration_log, +static MemoryListener xen_memory_listener = { + .region_add = xen_region_add, + .region_del = xen_region_del, .log_start = xen_log_start, .log_stop = xen_log_stop, + .log_sync = xen_log_sync, + .log_global_start = xen_log_global_start, + .log_global_stop = xen_log_global_stop, }; /* VCPU Operations, MMIO, IO ring ... */ @@ -946,9 +971,9 @@ int xen_hvm_init(void) qemu_add_vm_change_state_handler(xen_hvm_change_state_handler, state); - state->client = xen_cpu_phys_memory_client; + state->memory_listener = xen_memory_listener; QLIST_INIT(&state->physmap); - cpu_register_phys_memory_client(&state->client); + memory_listener_register(&state->memory_listener); state->log_for_dirtybit = NULL; /* Initialize backend core & drivers */ @@ -982,3 +1007,8 @@ void destroy_hvm_domain(void) xc_interface_close(xc_handle); } } + +void xen_register_framebuffer(MemoryRegion *mr) +{ + framebuffer = mr; +} diff --git a/xen-stub.c b/xen-stub.c index 5fa400faae1704b4a766d40b137e8dea64a20e1b..d403d864b3600ec906b508a85663de9d800e4740 100644 --- a/xen-stub.c +++ b/xen-stub.c @@ -44,3 +44,7 @@ int xen_init(void) { return -ENOSYS; } + +void xen_register_framebuffer(MemoryRegion *mr) +{ +}