From 62ec4832ea1093b20a8a0893a016a00ef8145496 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 8 Dec 2011 15:57:34 +0200 Subject: [PATCH 01/22] sysbus: add sysbus_address_space() Given a bus device, retrieves the memory address space for its bus. Signed-off-by: Avi Kivity --- hw/sysbus.c | 5 +++++ hw/sysbus.h | 1 + 2 files changed, 6 insertions(+) diff --git a/hw/sysbus.c b/hw/sysbus.c index 81a57bdba8..7016903163 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -261,3 +261,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 2f4025b221..899756bf7f 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, From 8ea9252abe08631611effb905fbb4a015ec1514c Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 8 Dec 2011 15:58:43 +0200 Subject: [PATCH 02/22] memory: add memory_region_is_ram() Signed-off-by: Avi Kivity --- memory.c | 8 ++++++++ memory.h | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/memory.c b/memory.c index a7e615ad15..4264b42222 100644 --- a/memory.c +++ b/memory.c @@ -832,6 +832,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 +999,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 +1013,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 +1069,11 @@ uint64_t memory_region_size(MemoryRegion *mr) return int128_get64(mr->size); } +bool memory_region_is_ram(MemoryRegion *mr) +{ + return mr->ram; +} + void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset) { mr->offset = offset; diff --git a/memory.h b/memory.h index fe643ff05b..dccc9007df 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; @@ -266,6 +267,15 @@ 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_get_ram_ptr: Get a pointer into a RAM memory region. * From ce7923da4da4e5895ab737fbf2c9b603c764a933 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 8 Dec 2011 16:05:11 +0200 Subject: [PATCH 03/22] memory: add memory_region_is_rom() Signed-off-by: Avi Kivity --- memory.c | 5 +++++ memory.h | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/memory.c b/memory.c index 4264b42222..01baeacf3c 100644 --- a/memory.c +++ b/memory.c @@ -1074,6 +1074,11 @@ bool memory_region_is_ram(MemoryRegion *mr) return mr->ram; } +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; diff --git a/memory.h b/memory.h index dccc9007df..91d6e8aef5 100644 --- a/memory.h +++ b/memory.h @@ -276,6 +276,15 @@ uint64_t memory_region_size(MemoryRegion *mr); */ bool memory_region_is_ram(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. * From 55043ba37ee4b080a4f4f77b0ff672be3cbf8825 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 15 Dec 2011 17:20:34 +0200 Subject: [PATCH 04/22] memory: add memory_region_is_logging() Signed-off-by: Avi Kivity --- memory.c | 5 +++++ memory.h | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/memory.c b/memory.c index 01baeacf3c..6e6163524b 100644 --- a/memory.c +++ b/memory.c @@ -1074,6 +1074,11 @@ 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; diff --git a/memory.h b/memory.h index 91d6e8aef5..87fb9740c7 100644 --- a/memory.h +++ b/memory.h @@ -276,6 +276,15 @@ uint64_t memory_region_size(MemoryRegion *mr); */ 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 * From e2177955a899483b19bd54e547db3b61db95eaf7 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 8 Dec 2011 15:00:18 +0200 Subject: [PATCH 05/22] memory: introduce memory_region_find() Given an address space (represented by the top-level memory region), returns the memory region that maps a given range. Useful for implementing DMA. The implementation is a simplistic binary search. Once we have a tree representation this can be optimized. Signed-off-by: Avi Kivity --- memory.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ memory.h | 39 +++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/memory.c b/memory.c index 6e6163524b..c3e64ba138 100644 --- a/memory.c +++ b/memory.c @@ -515,6 +515,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. */ @@ -1386,6 +1400,54 @@ void memory_region_set_alias_offset(MemoryRegion *mr, target_phys_addr_t offset) memory_region_update_topology(mr); } +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 set_system_memory_map(MemoryRegion *mr) { address_space_memory.root = mr; diff --git a/memory.h b/memory.h index 87fb9740c7..4d8f39ad09 100644 --- a/memory.h +++ b/memory.h @@ -148,6 +148,24 @@ 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 + * @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; + target_phys_addr_t offset_within_region; + uint64_t size; + target_phys_addr_t offset_within_address_space; +}; + /** * memory_region_init: Initialize a memory region * @@ -568,6 +586,27 @@ 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_region_transaction_begin: Start a transaction. * From 75c9d6c2f88f5713345b545beec10f0444ebd551 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 8 Dec 2011 16:00:54 +0200 Subject: [PATCH 06/22] framebuffer: drop use of cpu_get_physical_page_desc() cpu_get_physical_page_desc() is tied into the memory core's innards, replace it with uses of the API. Signed-off-by: Avi Kivity --- hw/framebuffer.c | 30 +++++++++++++----------------- hw/framebuffer.h | 3 +++ hw/milkymist-vgafb.c | 2 +- hw/omap_lcdc.c | 4 +++- hw/pl110.c | 2 +- hw/pxa2xx_lcd.c | 10 ++++++---- 6 files changed, 27 insertions(+), 24 deletions(-) diff --git a/hw/framebuffer.c b/hw/framebuffer.c index 56cf16e27a..3f4e77375c 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,27 +43,21 @@ 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); src_base = cpu_physical_memory_map(base, &src_len, 0); /* If we can't map the framebuffer then bail. We could try harder, @@ -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 a3a214649d..527a6b85f8 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/milkymist-vgafb.c b/hw/milkymist-vgafb.c index 01cd309ca3..108115e300 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 8484f7058d..f265306556 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 cc1eb6d986..303a9bcdbd 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 fd23d63a64..5dd4ef06d6 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); From dcc5cd33d27ab5612e0212b5399ad6ac0bc4886e Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 8 Dec 2011 16:12:18 +0200 Subject: [PATCH 07/22] loader: remove calls to cpu_get_physical_page_desc() cpu_get_physical_page_desc() is tied into the memory core's innards, replace it with uses of the API. Signed-off-by: Avi Kivity --- hw/loader.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/loader.c b/hw/loader.c index 9bbcddd424..446b62874e 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; From c1cd0b2c5131f24504d4513c4160cec73d53b326 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 15 Dec 2011 16:07:48 +0200 Subject: [PATCH 08/22] framebuffer: drop use of cpu_physical_sync_dirty_bitmap() Replace with memory API equivalent. Signed-off-by: Avi Kivity --- hw/framebuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/framebuffer.c b/hw/framebuffer.c index 3f4e77375c..b43bcdff40 100644 --- a/hw/framebuffer.c +++ b/hw/framebuffer.c @@ -50,7 +50,6 @@ void framebuffer_update_display( *first_row = -1; src_len = src_width * rows; - cpu_physical_sync_dirty_bitmap(base, base + src_len); mem_section = memory_region_find(address_space, base, src_len); if (mem_section.size != src_len || !memory_region_is_ram(mem_section.mr)) { return; @@ -59,6 +58,7 @@ void framebuffer_update_display( 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 From 86e775c654b775d3e295e8a33bb03cc03bdab68d Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 15 Dec 2011 16:24:49 +0200 Subject: [PATCH 09/22] memory: replace cpu_physical_sync_dirty_bitmap() with a memory API The function is still used as the implementation. Signed-off-by: Avi Kivity --- arch_init.c | 6 ++---- cpu-all.h | 3 --- exec-obsolete.h | 3 +++ memory.c | 4 ++++ memory.h | 10 ++++++++++ 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/arch_init.c b/arch_init.c index a411fdf263..ceef26ef17 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 9d787151e1..f2c53827ef 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -569,9 +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); diff --git a/exec-obsolete.h b/exec-obsolete.h index 34b9fc56bd..5e5c4c63fb 100644 --- a/exec-obsolete.h +++ b/exec-obsolete.h @@ -63,6 +63,9 @@ static inline void cpu_register_physical_memory(target_phys_addr_t start_addr, void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); +int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr); + #endif #endif diff --git a/memory.c b/memory.c index c3e64ba138..ef5d647acc 100644 --- a/memory.c +++ b/memory.c @@ -1447,6 +1447,10 @@ MemoryRegionSection memory_region_find(MemoryRegion *address_space, return ret; } +void memory_global_sync_dirty_bitmap(MemoryRegion *address_space) +{ + cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX); +} void set_system_memory_map(MemoryRegion *mr) { diff --git a/memory.h b/memory.h index 4d8f39ad09..8197b45804 100644 --- a/memory.h +++ b/memory.h @@ -607,6 +607,16 @@ void memory_region_set_alias_offset(MemoryRegion *mr, 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. * From 7664e80c84700d8b7e88ae854d1d74806c63f013 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 11 Dec 2011 14:47:25 +0200 Subject: [PATCH 10/22] memory: add API for observing updates to the physical memory map Add an API that allows a client to observe changes in the global memory map: - region added (possibly with logging enabled) - region removed (possibly with logging enabled) - logging started on a region - logging stopped on a region - global logging started - global logging removed This API will eventually replace cpu_register_physical_memory_client(). Signed-off-by: Avi Kivity --- exec.c | 5 +++ memory.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ memory.h | 47 ++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) diff --git a/exec.c b/exec.c index 32782b48c9..36b61c91ac 100644 --- a/exec.c +++ b/exec.c @@ -1762,6 +1762,11 @@ static int cpu_notify_sync_dirty_bitmap(target_phys_addr_t start, static int cpu_notify_migration_log(int enable) { CPUPhysMemoryClient *client; + if (enable) { + memory_global_dirty_log_start(); + } else { + memory_global_dirty_log_stop(); + } QLIST_FOREACH(client, &memory_client_list, list) { int r = client->migration_log(client, enable); if (r < 0) diff --git a/memory.c b/memory.c index ef5d647acc..61e324bbf9 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; @@ -697,6 +701,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, @@ -729,6 +759,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); } @@ -738,9 +769,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(frold, 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(frold, as, log_start); } } @@ -751,6 +784,7 @@ static void address_space_update_topology_pass(AddressSpace *as, if (adding) { as->ops->range_add(as, frnew); + MEMORY_LISTENER_UPDATE_REGION(frold, as, region_add); } ++inew; @@ -1130,6 +1164,7 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr) FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) { if (fr->mr == mr) { + MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory, log_sync); cpu_physical_sync_dirty_bitmap(int128_get64(fr->addr.start), int128_get64(addrrange_end(fr->addr))); } @@ -1449,7 +1484,65 @@ MemoryRegionSection memory_region_find(MemoryRegion *address_space, void memory_global_sync_dirty_bitmap(MemoryRegion *address_space) { + AddressSpace *as = memory_region_to_address_space(address_space); + FlatRange *fr; + cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX); + 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) diff --git a/memory.h b/memory.h index 8197b45804..5ba874e821 100644 --- a/memory.h +++ b/memory.h @@ -154,6 +154,7 @@ 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 @@ -161,11 +162,31 @@ typedef struct MemoryRegionSection MemoryRegionSection; */ 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 * @@ -631,6 +652,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 From 9f213ed92c5ccc3d0aa19359bb1783760d01dae9 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 15 Dec 2011 19:55:26 +0200 Subject: [PATCH 11/22] kvm: switch kvm slots to use host virtual address instead of ram_addr_t This simplifies a later switch to the memory API in slot management. Signed-off-by: Avi Kivity --- kvm-all.c | 29 +++++++++++++++++------------ kvm.h | 4 ++-- memory.c | 6 +++--- target-i386/kvm.c | 7 +++---- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/kvm-all.c b/kvm-all.c index ac048bce50..8d8f31e60d 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -50,7 +50,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 +146,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 +170,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; @@ -527,6 +526,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK; KVMSlot *mem, old; int err; + void *ram = NULL; /* kvm works in page size chunks, but the function may be called with sub-page size and unaligned start address. */ @@ -536,6 +536,10 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, /* KVM does not support read-only slots */ phys_offset &= ~IO_MEM_ROM; + if ((phys_offset & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { + ram = qemu_safe_ram_ptr(phys_offset); + } + while (1) { mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size); if (!mem) { @@ -544,7 +548,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, if (flags < IO_MEM_UNASSIGNED && 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); @@ -576,7 +580,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 = 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); @@ -588,6 +592,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 +602,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 +626,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); @@ -644,7 +649,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 = 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); diff --git a/kvm.h b/kvm.h index 243b063f92..c1de81a11c 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 61e324bbf9..9e3f87a110 100644 --- a/memory.c +++ b/memory.c @@ -769,11 +769,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(frold, as, log_stop); + 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(frold, as, log_start); + MEMORY_LISTENER_UPDATE_REGION(frnew, as, log_start); } } @@ -784,7 +784,7 @@ static void address_space_update_topology_pass(AddressSpace *as, if (adding) { as->ops->range_add(as, frnew); - MEMORY_LISTENER_UPDATE_REGION(frold, as, region_add); + MEMORY_LISTENER_UPDATE_REGION(frnew, as, region_add); } ++inew; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 5bfc21fc53..74d81efbd1 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; From a01672d3968cf91208666d371784110bfde9d4f8 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 18 Dec 2011 14:06:05 +0200 Subject: [PATCH 12/22] kvm: convert to MemoryListener API Drop the use of cpu_register_phys_memory_client() in favour of the new MemoryListener API. The new API simplifies the caller, since there is no need to deal with splitting and merging slots; however this is not exploited in this patch. Signed-off-by: Avi Kivity --- kvm-all.c | 107 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 37 deletions(-) diff --git a/kvm-all.c b/kvm-all.c index 8d8f31e60d..e3e4181ac9 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 @@ -289,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) @@ -519,13 +532,15 @@ 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 @@ -533,20 +548,19 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, 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 ((phys_offset & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { - ram = qemu_safe_ram_ptr(phys_offset); + 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); if (!mem) { 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) && (ram - start_addr == mem->ram - mem->start_addr)) { /* The new slot fits into the existing one and comes with @@ -575,8 +589,7 @@ 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; @@ -591,7 +604,6 @@ 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; @@ -642,8 +654,7 @@ 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); @@ -660,33 +671,55 @@ 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(start_addr, size, phys_offset, log_dirty); + kvm_set_phys_mem(section, true); } -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_region_del(MemoryListener *listener, + MemoryRegionSection *section) { - return kvm_physical_sync_dirty_bitmap(start_addr, end_addr); + kvm_set_phys_mem(section, false); } -static int kvm_client_migration_log(struct CPUPhysMemoryClient *client, - int enable) +static void kvm_log_sync(MemoryListener *listener, + MemoryRegionSection *section) { - return kvm_set_migration_log(enable); + target_phys_addr_t start = section->offset_within_address_space; + target_phys_addr_t end = start + section->size; + int r; + + r = kvm_physical_sync_dirty_bitmap(start, end); + if (r < 0) { + abort(); + } } -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 void kvm_log_global_start(struct MemoryListener *listener) +{ + int r; + + r = kvm_set_migration_log(1); + assert(r >= 0); +} + +static void kvm_log_global_stop(struct MemoryListener *listener) +{ + int r; + + r = kvm_set_migration_log(0); + assert(r >= 0); +} + +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) @@ -794,7 +827,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(); From 04097f7c5957273c578f72b9bd603ba6b1d69e33 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 18 Dec 2011 14:06:05 +0200 Subject: [PATCH 13/22] vhost: convert to MemoryListener API Drop the use of cpu_register_phys_memory_client() in favour of the new MemoryListener API. The new API simplifies the caller, since there is no need to deal with splitting and merging slots; however this is not exploited in this patch. Signed-off-by: Avi Kivity --- hw/vhost.c | 126 +++++++++++++++++++++++++++++++++++++++-------------- hw/vhost.h | 3 +- 2 files changed, 96 insertions(+), 33 deletions(-) diff --git a/hw/vhost.c b/hw/vhost.c index 0870cb7d85..a1c5e4cb85 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -57,12 +57,12 @@ static void vhost_dev_sync_region(struct vhost_dev *dev, } } -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, + 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; } @@ -81,6 +81,17 @@ static int vhost_client_sync_dirty_bitmap(CPUPhysMemoryClient *client, 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, 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, @@ -259,8 +270,7 @@ 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); + vhost_sync_dirty_bitmap(dev, 0, (target_phys_addr_t)~0x0ull); if (dev->log) { g_free(dev->log); } @@ -335,31 +345,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 +387,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 +425,18 @@ static void vhost_client_set_memory(CPUPhysMemoryClient *client, } } +static void vhost_region_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + vhost_set_memory(listener, section, true); +} + +static void vhost_region_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + vhost_set_memory(listener, section, false); +} + static int vhost_virtqueue_set_addr(struct vhost_dev *dev, struct vhost_virtqueue *vq, unsigned idx, bool enable_log) @@ -467,10 +494,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 +527,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 +704,21 @@ 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->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,7 +729,7 @@ 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); close(hdev->control); } @@ -808,8 +871,7 @@ 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); + vhost_sync_dirty_bitmap(hdev, 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 c9452f0732..d1824ec9d9 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,7 +27,7 @@ typedef unsigned long vhost_log_chunk_t; struct vhost_memory; struct vhost_dev { - CPUPhysMemoryClient client; + MemoryListener memory_listener; int control; struct vhost_memory *mem; struct vhost_virtqueue *vqs; From c65adf9bcdc9c3212d62696f1b52c8ce0f98dd7f Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 18 Dec 2011 16:40:50 +0200 Subject: [PATCH 14/22] xen, vga: add API for registering the framebuffer Xen currently uses the name of a memory region to determine whether it is the framebuffer. Replace with an explicit API. Signed-off-by: Avi Kivity --- hw/vga.c | 2 ++ hw/xen.h | 3 +++ xen-all.c | 6 ++++++ xen-stub.c | 4 ++++ 4 files changed, 15 insertions(+) diff --git a/hw/vga.c b/hw/vga.c index ca79aa157d..7e1dd5ac80 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/xen.h b/hw/xen.h index f9f66e83ef..b46879c6f7 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/xen-all.c b/xen-all.c index bd89889502..51315ce1aa 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 @@ -982,3 +983,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 5fa400faae..d403d864b3 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) +{ +} From e34911c420c617151fe5bc95a4b6f269cca0483b Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 19 Dec 2011 12:06:23 +0200 Subject: [PATCH 15/22] memory: temporarily add memory_region_get_ram_addr() This is a layering violation, but needed while the code contains naked calls to qemu_get_ram_ptr() and the like. Signed-off-by: Avi Kivity --- memory.c | 6 ++++++ memory.h | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/memory.c b/memory.c index 9e3f87a110..6a637d4e5b 100644 --- a/memory.c +++ b/memory.c @@ -1435,6 +1435,12 @@ 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_; diff --git a/memory.h b/memory.h index 5ba874e821..a82226a752 100644 --- a/memory.h +++ b/memory.h @@ -558,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. * From 20581d207853fe4b1af88b116f077516dfa888cd Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 19 Dec 2011 12:07:50 +0200 Subject: [PATCH 16/22] xen: convert to MemoryListener API Signed-off-by: Avi Kivity --- trace-events | 2 +- xen-all.c | 138 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 82 insertions(+), 58 deletions(-) diff --git a/trace-events b/trace-events index 514849aed8..5781a69b0b 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 51315ce1aa..dc232651e7 100644 --- a/xen-all.c +++ b/xen-all.c @@ -63,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; @@ -80,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; @@ -226,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; @@ -245,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; @@ -334,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; } @@ -347,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; } - trace_xen_client_set_memory(start_addr, size, phys_offset, log_dirty); + if (!(section->mr != &ram_memory + && ( (log_dirty && add) || (!log_dirty && !add)))) { + return; + } + + 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) @@ -433,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) { - 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 void xen_log_global_stop(MemoryListener *listener) +{ +} + +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 ... */ @@ -947,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 */ From dcd97e33af43ae0bfa7e8c39ce8cebcfe7af6cb4 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 19 Dec 2011 12:53:48 +0200 Subject: [PATCH 17/22] memory: remove CPUPhysMemoryClient No longer used. Signed-off-by: Avi Kivity --- cpu-all.h | 6 -- cpu-common.h | 23 ------- exec-obsolete.h | 3 - exec.c | 169 ++---------------------------------------------- memory.c | 12 ---- 5 files changed, 5 insertions(+), 208 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index f2c53827ef..734833abda 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -569,12 +569,6 @@ int cpu_physical_memory_set_dirty_tracking(int enable); int cpu_physical_memory_get_dirty_tracking(void); -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 8295e4fea4..eee2fafe86 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -71,29 +71,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-obsolete.h b/exec-obsolete.h index 5e5c4c63fb..34b9fc56bd 100644 --- a/exec-obsolete.h +++ b/exec-obsolete.h @@ -63,9 +63,6 @@ static inline void cpu_register_physical_memory(target_phys_addr_t start_addr, void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); -int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, - target_phys_addr_t end_addr); - #endif #endif diff --git a/exec.c b/exec.c index 36b61c91ac..e1f7462eeb 100644 --- a/exec.c +++ b/exec.c @@ -1732,129 +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; - if (enable) { - memory_global_dirty_log_start(); - } else { - memory_global_dirty_log_stop(); - } - 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) @@ -2131,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; } @@ -2140,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; @@ -2681,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; diff --git a/memory.c b/memory.c index 6a637d4e5b..a90eefd8d1 100644 --- a/memory.c +++ b/memory.c @@ -338,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); @@ -350,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) @@ -1165,8 +1156,6 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr) FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) { if (fr->mr == mr) { MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory, log_sync); - cpu_physical_sync_dirty_bitmap(int128_get64(fr->addr.start), - int128_get64(addrrange_end(fr->addr))); } } } @@ -1493,7 +1482,6 @@ void memory_global_sync_dirty_bitmap(MemoryRegion *address_space) AddressSpace *as = memory_region_to_address_space(address_space); FlatRange *fr; - cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX); FOR_EACH_FLAT_RANGE(fr, &as->current_map) { MEMORY_LISTENER_UPDATE_REGION(fr, as, log_sync); } From ffcde12f6ca9fd9701e238ce9909314a0123f553 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 19 Dec 2011 13:18:13 +0200 Subject: [PATCH 18/22] kvm: avoid cpu_get_physical_page_desc() This reaches into the innards of the memory core, which are being changed. Switch to a memory API version. Signed-off-by: Avi Kivity --- kvm-all.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/kvm-all.c b/kvm-all.c index e3e4181ac9..3174f42a37 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -340,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...) @@ -363,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); } } @@ -382,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) { @@ -428,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); @@ -686,11 +681,9 @@ static void kvm_region_del(MemoryListener *listener, static void kvm_log_sync(MemoryListener *listener, MemoryRegionSection *section) { - target_phys_addr_t start = section->offset_within_address_space; - target_phys_addr_t end = start + section->size; int r; - r = kvm_physical_sync_dirty_bitmap(start, end); + r = kvm_physical_sync_dirty_bitmap(section); if (r < 0) { abort(); } From 2817b260e3ca57ee091fc56403bfafdcc18b6a96 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 19 Dec 2011 13:18:13 +0200 Subject: [PATCH 19/22] vhost: avoid cpu_get_physical_page_desc() This reaches into the innards of the memory core, which are being changed. Switch to a memory API version. Signed-off-by: Avi Kivity --- hw/vhost.c | 47 +++++++++++++++++++++++++++++++++++++++-------- hw/vhost.h | 2 ++ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/hw/vhost.c b/hw/vhost.c index a1c5e4cb85..cd56e75d0a 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,8 +50,8 @@ 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; @@ -58,6 +59,7 @@ static void vhost_dev_sync_region(struct vhost_dev *dev, } static int vhost_sync_dirty_bitmap(struct vhost_dev *dev, + MemoryRegionSection *section, target_phys_addr_t start_addr, target_phys_addr_t end_addr) { @@ -68,14 +70,14 @@ static int vhost_sync_dirty_bitmap(struct vhost_dev *dev, } 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; @@ -89,7 +91,7 @@ static void vhost_log_sync(MemoryListener *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, start_addr, end_addr); + vhost_sync_dirty_bitmap(dev, section, start_addr, end_addr); } /* Assign/unassign. Keep an unsorted array of non-overlapping @@ -261,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 { @@ -270,7 +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_sync_dirty_bitmap(dev, 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); } @@ -428,13 +433,33 @@ static void vhost_set_memory(MemoryListener *listener, 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, @@ -714,6 +739,8 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force) .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; @@ -731,6 +758,7 @@ void vhost_dev_cleanup(struct vhost_dev *hdev) { memory_listener_unregister(&hdev->memory_listener); g_free(hdev->mem); + g_free(hdev->mem_sections); close(hdev->control); } @@ -871,7 +899,10 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) hdev->vqs + i, i); } - vhost_sync_dirty_bitmap(hdev, 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 d1824ec9d9..80e64df860 100644 --- a/hw/vhost.h +++ b/hw/vhost.h @@ -30,6 +30,8 @@ struct vhost_dev { 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; From b7c28c74af51e07fc457fef47ac4ec6b1e654d2c Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 19 Dec 2011 13:18:13 +0200 Subject: [PATCH 20/22] virtio-balloon: avoid cpu_get_physical_page_desc() This reaches into the innards of the memory core, which are being changed. Switch to a memory API version. Signed-off-by: Avi Kivity --- hw/virtio-balloon.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index e24a2bf1f3..ce9d2c9759 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); From cc4aa8307c83111a0c804ae3eaf1e63f220c682e Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 19 Dec 2011 13:18:13 +0200 Subject: [PATCH 21/22] sparc: avoid cpu_get_physical_page_desc() This reaches into the innards of the memory core, which are being changed. Switch to a memory API version. Signed-off-by: Avi Kivity --- target-sparc/mmu_helper.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c index 8cdc224ae3..bdff1c3254 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; From 586c6230c012d1aced38e5a5614d15052ca4ae7a Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 19 Dec 2011 16:01:08 +0200 Subject: [PATCH 22/22] Remove cpu_get_physical_page_desc() No longer used. Signed-off-by: Avi Kivity --- cpu-common.h | 1 - exec.c | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/cpu-common.h b/cpu-common.h index eee2fafe86..3fe44d25d1 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); diff --git a/exec.c b/exec.c index e1f7462eeb..b02199b271 100644 --- a/exec.c +++ b/exec.c @@ -2595,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())