diff options
Diffstat (limited to 'memory.c')
-rw-r--r-- | memory.c | 149 |
1 files changed, 105 insertions, 44 deletions
@@ -23,11 +23,13 @@ #include "exec/memory-internal.h" #include "exec/ram_addr.h" +#include "sysemu/sysemu.h" //#define DEBUG_UNASSIGNED static unsigned memory_region_transaction_depth; static bool memory_region_update_pending; +static bool ioeventfd_update_pending; static bool global_dirty_log = false; /* flat_view_mutex is taken around reading as->current_map; the critical @@ -484,15 +486,15 @@ static AddressSpace *memory_region_to_address_space(MemoryRegion *mr) { AddressSpace *as; - while (mr->parent) { - mr = mr->parent; + while (mr->container) { + mr = mr->container; } QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { if (mr == as->root) { return as; } } - abort(); + return NULL; } /* Render a memory region into the global view. Ranges in @view obscure @@ -786,22 +788,34 @@ void memory_region_transaction_begin(void) ++memory_region_transaction_depth; } +static void memory_region_clear_pending(void) +{ + memory_region_update_pending = false; + ioeventfd_update_pending = false; +} + void memory_region_transaction_commit(void) { AddressSpace *as; assert(memory_region_transaction_depth); --memory_region_transaction_depth; - if (!memory_region_transaction_depth && memory_region_update_pending) { - memory_region_update_pending = false; - MEMORY_LISTENER_CALL_GLOBAL(begin, Forward); + if (!memory_region_transaction_depth) { + if (memory_region_update_pending) { + MEMORY_LISTENER_CALL_GLOBAL(begin, Forward); - QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { - address_space_update_topology(as); - } + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + address_space_update_topology(as); + } - MEMORY_LISTENER_CALL_GLOBAL(commit, Forward); - } + MEMORY_LISTENER_CALL_GLOBAL(commit, Forward); + } else if (ioeventfd_update_pending) { + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + address_space_update_ioeventfds(as); + } + } + memory_region_clear_pending(); + } } static void memory_region_destructor_none(MemoryRegion *mr) @@ -837,7 +851,7 @@ void memory_region_init(MemoryRegion *mr, mr->opaque = NULL; mr->owner = owner; mr->iommu_ops = NULL; - mr->parent = NULL; + mr->container = NULL; mr->size = int128_make64(size); if (size == UINT64_MAX) { mr->size = int128_2_64(); @@ -1019,6 +1033,23 @@ void memory_region_init_ram(MemoryRegion *mr, mr->ram_addr = qemu_ram_alloc(size, mr); } +#ifdef __linux__ +void memory_region_init_ram_from_file(MemoryRegion *mr, + struct Object *owner, + const char *name, + uint64_t size, + bool share, + const char *path, + Error **errp) +{ + memory_region_init(mr, owner, name, size); + mr->ram = true; + mr->terminates = true; + mr->destructor = memory_region_destructor_ram; + mr->ram_addr = qemu_ram_alloc_from_file(size, mr, share, path, errp); +} +#endif + void memory_region_init_ram_ptr(MemoryRegion *mr, Object *owner, const char *name, @@ -1241,6 +1272,17 @@ void memory_region_reset_dirty(MemoryRegion *mr, hwaddr addr, cpu_physical_memory_reset_dirty(mr->ram_addr + addr, size, client); } +int memory_region_get_fd(MemoryRegion *mr) +{ + if (mr->alias) { + return memory_region_get_fd(mr->alias); + } + + assert(mr->terminates); + + return qemu_get_ram_fd(mr->ram_addr & TARGET_PAGE_MASK); +} + void *memory_region_get_ram_ptr(MemoryRegion *mr) { if (mr->alias) { @@ -1319,6 +1361,7 @@ void memory_region_add_coalescing(MemoryRegion *mr, void memory_region_clear_coalescing(MemoryRegion *mr) { CoalescedMemoryRange *cmr; + bool updated = false; qemu_flush_coalesced_mmio_buffer(); mr->flush_coalesced_mmio = false; @@ -1327,8 +1370,12 @@ void memory_region_clear_coalescing(MemoryRegion *mr) cmr = QTAILQ_FIRST(&mr->coalesced); QTAILQ_REMOVE(&mr->coalesced, cmr, link); g_free(cmr); + updated = true; + } + + if (updated) { + memory_region_update_coalesced_range(mr); } - memory_region_update_coalesced_range(mr); } void memory_region_set_flush_coalesced(MemoryRegion *mr) @@ -1373,7 +1420,7 @@ void memory_region_add_eventfd(MemoryRegion *mr, memmove(&mr->ioeventfds[i+1], &mr->ioeventfds[i], sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb-1 - i)); mr->ioeventfds[i] = mrfd; - memory_region_update_pending |= mr->enabled; + ioeventfd_update_pending |= mr->enabled; memory_region_transaction_commit(); } @@ -1406,22 +1453,19 @@ void memory_region_del_eventfd(MemoryRegion *mr, --mr->ioeventfd_nb; mr->ioeventfds = g_realloc(mr->ioeventfds, sizeof(*mr->ioeventfds)*mr->ioeventfd_nb + 1); - memory_region_update_pending |= mr->enabled; + ioeventfd_update_pending |= mr->enabled; memory_region_transaction_commit(); } -static void memory_region_add_subregion_common(MemoryRegion *mr, - hwaddr offset, - MemoryRegion *subregion) +static void memory_region_update_container_subregions(MemoryRegion *subregion) { + hwaddr offset = subregion->addr; + MemoryRegion *mr = subregion->container; MemoryRegion *other; memory_region_transaction_begin(); - assert(!subregion->parent); memory_region_ref(subregion); - subregion->parent = mr; - subregion->addr = offset; QTAILQ_FOREACH(other, &mr->subregions, subregions_link) { if (subregion->may_overlap || other->may_overlap) { continue; @@ -1455,6 +1499,15 @@ done: memory_region_transaction_commit(); } +static void memory_region_add_subregion_common(MemoryRegion *mr, + hwaddr offset, + MemoryRegion *subregion) +{ + assert(!subregion->container); + subregion->container = mr; + subregion->addr = offset; + memory_region_update_container_subregions(subregion); +} void memory_region_add_subregion(MemoryRegion *mr, hwaddr offset, @@ -1479,8 +1532,8 @@ void memory_region_del_subregion(MemoryRegion *mr, MemoryRegion *subregion) { memory_region_transaction_begin(); - assert(subregion->parent == mr); - subregion->parent = NULL; + assert(subregion->container == mr); + subregion->container = NULL; QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link); memory_region_unref(subregion); memory_region_update_pending |= mr->enabled && subregion->enabled; @@ -1498,27 +1551,27 @@ void memory_region_set_enabled(MemoryRegion *mr, bool enabled) memory_region_transaction_commit(); } -void memory_region_set_address(MemoryRegion *mr, hwaddr addr) +static void memory_region_readd_subregion(MemoryRegion *mr) { - MemoryRegion *parent = mr->parent; - int priority = mr->priority; - bool may_overlap = mr->may_overlap; + MemoryRegion *container = mr->container; - if (addr == mr->addr || !parent) { - mr->addr = addr; - return; + if (container) { + memory_region_transaction_begin(); + memory_region_ref(mr); + memory_region_del_subregion(container, mr); + mr->container = container; + memory_region_update_container_subregions(mr); + memory_region_unref(mr); + memory_region_transaction_commit(); } +} - memory_region_transaction_begin(); - memory_region_ref(mr); - memory_region_del_subregion(parent, mr); - if (may_overlap) { - memory_region_add_subregion_overlap(parent, addr, mr, priority); - } else { - memory_region_add_subregion(parent, addr, mr); +void memory_region_set_address(MemoryRegion *mr, hwaddr addr) +{ + if (addr != mr->addr) { + mr->addr = addr; + memory_region_readd_subregion(mr); } - memory_region_unref(mr); - memory_region_transaction_commit(); } void memory_region_set_alias_offset(MemoryRegion *mr, hwaddr offset) @@ -1559,16 +1612,21 @@ static FlatRange *flatview_lookup(FlatView *view, AddrRange addr) sizeof(FlatRange), cmp_flatrange_addr); } -bool memory_region_present(MemoryRegion *parent, hwaddr addr) +bool memory_region_present(MemoryRegion *container, hwaddr addr) { - MemoryRegion *mr = memory_region_find(parent, addr, 1).mr; - if (!mr || (mr == parent)) { + MemoryRegion *mr = memory_region_find(container, addr, 1).mr; + if (!mr || (mr == container)) { return false; } memory_region_unref(mr); return true; } +bool memory_region_is_mapped(MemoryRegion *mr) +{ + return mr->container ? true : false; +} + MemoryRegionSection memory_region_find(MemoryRegion *mr, hwaddr addr, uint64_t size) { @@ -1580,12 +1638,15 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr, FlatRange *fr; addr += mr->addr; - for (root = mr; root->parent; ) { - root = root->parent; + for (root = mr; root->container; ) { + root = root->container; addr += root->addr; } as = memory_region_to_address_space(root); + if (!as) { + return ret; + } range = addrrange_make(int128_make64(addr), int128_make64(size)); view = address_space_get_flatview(as); |