From eb4c0f18e96763963dd5db50993a16a776a4ab67 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Tue, 26 Jun 2018 12:25:44 -0700 Subject: [PATCH] [Core Change] Port memory region aliasing from XQEMU 1.x --- include/exec/memory.h | 21 +++++++++++++ include/exec/ram_addr.h | 13 +++++++- include/exec/ramlist.h | 3 +- memory.c | 66 +++++++++++++++++++++++++++++++++++++---- 4 files changed, 96 insertions(+), 7 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index 31eae0a640..9e5c741a68 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1133,6 +1133,25 @@ bool memory_region_get_dirty(MemoryRegion *mr, hwaddr addr, void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr, hwaddr size); +bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr, + hwaddr size, unsigned client); + +/** + * memory_region_set_client_dirty: Mark a range of bytes as dirty + * in a memory region for a specified client. + * + * Marks a range of bytes as dirty, after it has been dirtied outside + * guest code. + * + * @mr: the memory region being dirtied. + * @addr: the address (relative to the start of the region) being dirtied. + * @size: size of the range being dirtied. + * @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or + * %DIRTY_MEMORY_VGA. + */ +void memory_region_set_client_dirty(MemoryRegion *mr, hwaddr addr, + hwaddr size, unsigned client); + /** * memory_region_snapshot_and_clear_dirty: Get a snapshot of the dirty * bitmap and clear it. @@ -2012,6 +2031,8 @@ address_space_write_cached(MemoryRegionCache *cache, hwaddr addr, address_space_write(cache->as, cache->xlat + addr, MEMTXATTRS_UNSPECIFIED, buf, len); } +void memory_region_destroy(MemoryRegion *mr); + #endif #endif diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index cf2446a176..45cab31f18 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -184,11 +184,12 @@ static inline bool cpu_physical_memory_get_dirty_flag(ram_addr_t addr, static inline bool cpu_physical_memory_is_clean(ram_addr_t addr) { + bool nv2a = cpu_physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_NV2A); bool vga = cpu_physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_VGA); bool code = cpu_physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_CODE); bool migration = cpu_physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_MIGRATION); - return !(vga && code && migration); + return !(nv2a && vga && code && migration); } static inline uint8_t cpu_physical_memory_range_includes_clean(ram_addr_t start, @@ -197,6 +198,10 @@ static inline uint8_t cpu_physical_memory_range_includes_clean(ram_addr_t start, { uint8_t ret = 0; + if (mask & (1 << DIRTY_MEMORY_NV2A) && + !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_NV2A)) { + ret |= (1 << DIRTY_MEMORY_NV2A); + } if (mask & (1 << DIRTY_MEMORY_VGA) && !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_VGA)) { ret |= (1 << DIRTY_MEMORY_VGA); @@ -269,6 +274,10 @@ static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start, bitmap_set_atomic(blocks[DIRTY_MEMORY_VGA]->blocks[idx], offset, next - page); } + if (unlikely(mask & (1 << DIRTY_MEMORY_NV2A))) { + bitmap_set_atomic(blocks[DIRTY_MEMORY_NV2A]->blocks[idx], + offset, next - page); + } if (unlikely(mask & (1 << DIRTY_MEMORY_CODE))) { bitmap_set_atomic(blocks[DIRTY_MEMORY_CODE]->blocks[idx], offset, next - page); @@ -323,6 +332,7 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, atomic_or(&blocks[DIRTY_MEMORY_MIGRATION][idx][offset], temp); atomic_or(&blocks[DIRTY_MEMORY_VGA][idx][offset], temp); + atomic_or(&blocks[DIRTY_MEMORY_NV2A][idx][offset], temp); if (tcg_enabled()) { atomic_or(&blocks[DIRTY_MEMORY_CODE][idx][offset], temp); } @@ -377,6 +387,7 @@ static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start, { cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_MIGRATION); cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_VGA); + cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_NV2A); cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_CODE); } diff --git a/include/exec/ramlist.h b/include/exec/ramlist.h index 2e2ac6cb99..b85bd709a4 100644 --- a/include/exec/ramlist.h +++ b/include/exec/ramlist.h @@ -11,7 +11,8 @@ typedef struct RAMBlockNotifier RAMBlockNotifier; #define DIRTY_MEMORY_VGA 0 #define DIRTY_MEMORY_CODE 1 #define DIRTY_MEMORY_MIGRATION 2 -#define DIRTY_MEMORY_NUM 3 /* num of dirty bits */ +#define DIRTY_MEMORY_NV2A 3 +#define DIRTY_MEMORY_NUM 4 /* num of dirty bits */ /* The dirty memory bitmap is split into fixed-size blocks to allow growth * under RCU. The bitmap for a block can be accessed as follows: diff --git a/memory.c b/memory.c index e70b64b8b9..b273531e1c 100644 --- a/memory.c +++ b/memory.c @@ -1701,6 +1701,16 @@ static void memory_region_finalize(Object *obj) g_free(mr->ioeventfds); } +void memory_region_destroy(MemoryRegion *mr) +{ + assert(QTAILQ_EMPTY(&mr->subregions)); + assert(memory_region_transaction_depth == 0); + mr->destructor(mr); + memory_region_clear_coalescing(mr); + g_free((char *)mr->name); + g_free(mr->ioeventfds); +} + Object *memory_region_owner(MemoryRegion *mr) { Object *obj = OBJECT(mr); @@ -1919,12 +1929,9 @@ int memory_region_iommu_get_attr(IOMMUMemoryRegion *iommu_mr, void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client) { uint8_t mask = 1 << client; - uint8_t old_logging; - assert(client == DIRTY_MEMORY_VGA); - old_logging = mr->vga_logging_count; - mr->vga_logging_count += log ? 1 : -1; - if (!!old_logging == !!mr->vga_logging_count) { + if (mr->alias) { + memory_region_set_log(mr->alias, log, client); return; } @@ -1937,6 +1944,10 @@ void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client) bool memory_region_get_dirty(MemoryRegion *mr, hwaddr addr, hwaddr size, unsigned client) { + if (mr->alias) { + return memory_region_get_dirty(mr->alias, addr - mr->alias_offset, + size, client); + } assert(mr->ram_block); return cpu_physical_memory_get_dirty(memory_region_get_ram_addr(mr) + addr, size, client); @@ -1945,12 +1956,42 @@ bool memory_region_get_dirty(MemoryRegion *mr, hwaddr addr, void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr, hwaddr size) { + if (mr->alias) { + return memory_region_set_dirty(mr->alias, addr - mr->alias_offset, + size); + } assert(mr->ram_block); cpu_physical_memory_set_dirty_range(memory_region_get_ram_addr(mr) + addr, size, memory_region_get_dirty_log_mask(mr)); } +void memory_region_set_client_dirty(MemoryRegion *mr, hwaddr addr, + hwaddr size, unsigned client) +{ + if (mr->alias) { + return memory_region_set_client_dirty(mr->alias, + addr - mr->alias_offset, + size, client); + } + assert(mr->terminates); + return cpu_physical_memory_set_dirty_range(memory_region_get_ram_addr(mr) + addr, + size, 1 << client); +} + +bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr, + hwaddr size, unsigned client) +{ + if (mr->alias) { + return memory_region_test_and_clear_dirty(mr->alias, + addr - mr->alias_offset, + size, client); + } + assert(mr->terminates); + return cpu_physical_memory_test_and_clear_dirty( + memory_region_get_ram_addr(mr) + addr, size, client); +} + static void memory_region_sync_dirty_bitmap(MemoryRegion *mr) { MemoryListener *listener; @@ -1984,6 +2025,9 @@ DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr, hwaddr size, unsigned client) { + if (mr->alias) { + return memory_region_snapshot_and_clear_dirty(mr->alias, addr - mr->alias_offset, size, client); + } assert(mr->ram_block); memory_region_sync_dirty_bitmap(mr); return cpu_physical_memory_snapshot_and_clear_dirty( @@ -1993,6 +2037,9 @@ DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr, bool memory_region_snapshot_get_dirty(MemoryRegion *mr, DirtyBitmapSnapshot *snap, hwaddr addr, hwaddr size) { + if (mr->alias) { + return memory_region_snapshot_get_dirty(mr->alias, snap, addr - mr->alias_offset, size); + } assert(mr->ram_block); return cpu_physical_memory_snapshot_get_dirty(snap, memory_region_get_ram_addr(mr) + addr, size); @@ -2021,6 +2068,11 @@ void memory_region_rom_device_set_romd(MemoryRegion *mr, bool romd_mode) void memory_region_reset_dirty(MemoryRegion *mr, hwaddr addr, hwaddr size, unsigned client) { + if (mr->alias) { + memory_region_reset_dirty(mr->alias, addr - mr->alias_offset, + size, client); + return; + } assert(mr->ram_block); cpu_physical_memory_test_and_clear_dirty( memory_region_get_ram_addr(mr) + addr, size, client); @@ -2045,6 +2097,10 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr) void *ptr; uint64_t offset = 0; + if (mr->alias) { + return memory_region_get_ram_ptr(mr->alias) + mr->alias_offset; + } + rcu_read_lock(); while (mr->alias) { offset += mr->alias_offset;