[Core Change] Port memory region aliasing from XQEMU 1.x

This commit is contained in:
Matt Borgerson 2018-06-26 12:25:44 -07:00
parent 3f557e6d45
commit eb4c0f18e9
4 changed files with 96 additions and 7 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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:

View File

@ -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;