diff --git a/exec.c b/exec.c index 759055d0e3..f0e2bd32b6 100644 --- a/exec.c +++ b/exec.c @@ -2066,10 +2066,8 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, static void invalidate_and_set_dirty(hwaddr addr, hwaddr length) { - if (cpu_physical_memory_is_clean(addr)) { - /* invalidate code */ - tb_invalidate_phys_page_range(addr, addr + length, 0); - /* set dirty bit */ + if (cpu_physical_memory_range_includes_clean(addr, length)) { + tb_invalidate_phys_range(addr, addr + length, 0); cpu_physical_memory_set_dirty_range_nocode(addr, length); } xen_modified_memory(addr, length); diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index cf1d4c7e1f..8fc75cdd2b 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -49,6 +49,21 @@ static inline bool cpu_physical_memory_get_dirty(ram_addr_t start, return next < end; } +static inline bool cpu_physical_memory_get_clean(ram_addr_t start, + ram_addr_t length, + unsigned client) +{ + unsigned long end, page, next; + + assert(client < DIRTY_MEMORY_NUM); + + end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS; + page = start >> TARGET_PAGE_BITS; + next = find_next_zero_bit(ram_list.dirty_memory[client], end, page); + + return next < end; +} + static inline bool cpu_physical_memory_get_dirty_flag(ram_addr_t addr, unsigned client) { @@ -64,6 +79,16 @@ static inline bool cpu_physical_memory_is_clean(ram_addr_t addr) return !(vga && code && migration); } +static inline bool cpu_physical_memory_range_includes_clean(ram_addr_t start, + ram_addr_t length) +{ + bool vga = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_VGA); + bool code = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_CODE); + bool migration = + cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_MIGRATION); + return vga || code || migration; +} + static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr, unsigned client) {