diff --git a/MAINTAINERS b/MAINTAINERS index 51a6f51842be9b57768b8f5fdd05e36b137cd547..d1a340559da695b2f52d27bd0c8068504431d254 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -726,6 +726,16 @@ S: Odd Fixes F: gdbstub* F: gdb-xml/ +Memory API +M: Paolo Bonzini +S: Supported +F: include/exec/ioport.h +F: ioport.c +F: include/exec/memory.h +F: memory.c +F: include/exec/memory-internal.h +F: exec.c + SPICE M: Gerd Hoffmann S: Supported diff --git a/cpus.c b/cpus.c index dd7ac136215170bc17d3a6aef9a3d32b7c9dff71..af06dc0ae6fb4a1186b5246dd1e1090b5afbc100 100644 --- a/cpus.c +++ b/cpus.c @@ -347,7 +347,7 @@ void qtest_clock_warp(int64_t dest) assert(qtest_enabled()); while (clock < dest) { int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); - int64_t warp = MIN(dest - clock, deadline); + int64_t warp = qemu_soonest_timeout(dest - clock, deadline); seqlock_write_lock(&timers_state.vm_clock_seqlock); qemu_icount_bias += warp; seqlock_write_unlock(&timers_state.vm_clock_seqlock); diff --git a/exec.c b/exec.c index 4e179a6f66e736e7d8741ee3b568945dd02cd04c..c3fbbb3fb8b632deba529fc2e63826d17d0e45cd 100644 --- a/exec.c +++ b/exec.c @@ -1201,17 +1201,24 @@ static void qemu_ram_setup_dump(void *addr, ram_addr_t size) } } -void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev) +static RAMBlock *find_ram_block(ram_addr_t addr) { - RAMBlock *new_block, *block; + RAMBlock *block; - new_block = NULL; QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (block->offset == addr) { - new_block = block; - break; + return block; } } + + return NULL; +} + +void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev) +{ + RAMBlock *new_block = find_ram_block(addr); + RAMBlock *block; + assert(new_block); assert(!new_block->idstr[0]); @@ -1236,6 +1243,15 @@ void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev) qemu_mutex_unlock_ramlist(); } +void qemu_ram_unset_idstr(ram_addr_t addr) +{ + RAMBlock *block = find_ram_block(addr); + + if (block) { + memset(block->idstr, 0, sizeof(block->idstr)); + } +} + static int memory_try_enable_merging(void *addr, size_t len) { if (!qemu_opt_get_bool(qemu_get_machine_opts(), "mem-merge", true)) { @@ -1760,10 +1776,12 @@ static subpage_t *subpage_init(AddressSpace *as, hwaddr base) return mmio; } -static uint16_t dummy_section(PhysPageMap *map, MemoryRegion *mr) +static uint16_t dummy_section(PhysPageMap *map, AddressSpace *as, + MemoryRegion *mr) { + assert(as); MemoryRegionSection section = { - .address_space = &address_space_memory, + .address_space = as, .mr = mr, .offset_within_address_space = 0, .offset_within_region = 0, @@ -1795,13 +1813,13 @@ static void mem_begin(MemoryListener *listener) AddressSpaceDispatch *d = g_new0(AddressSpaceDispatch, 1); uint16_t n; - n = dummy_section(&d->map, &io_mem_unassigned); + n = dummy_section(&d->map, as, &io_mem_unassigned); assert(n == PHYS_SECTION_UNASSIGNED); - n = dummy_section(&d->map, &io_mem_notdirty); + n = dummy_section(&d->map, as, &io_mem_notdirty); assert(n == PHYS_SECTION_NOTDIRTY); - n = dummy_section(&d->map, &io_mem_rom); + n = dummy_section(&d->map, as, &io_mem_rom); assert(n == PHYS_SECTION_ROM); - n = dummy_section(&d->map, &io_mem_watch); + n = dummy_section(&d->map, as, &io_mem_watch); assert(n == PHYS_SECTION_WATCH); d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 }; diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index a21b65a893b13d7c514100c424217b14d5755028..89ec6404cff3cfebd9f9222fc85354268f34fe9e 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -54,6 +54,7 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length); /* This should not be used by devices. */ MemoryRegion *qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr); void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev); +void qemu_ram_unset_idstr(ram_addr_t addr); void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf, int len, int is_write); diff --git a/include/exec/memory.h b/include/exec/memory.h index 1d55ad94a4982745badd3f6d14f12cb985dba2f6..549ae734e61786d2153e022ab5f92a82077f2693 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -135,7 +135,7 @@ struct MemoryRegion { const MemoryRegionIOMMUOps *iommu_ops; void *opaque; struct Object *owner; - MemoryRegion *parent; + MemoryRegion *container; Int128 size; hwaddr addr; void (*destructor)(MemoryRegion *mr); @@ -815,11 +815,11 @@ void memory_region_set_enabled(MemoryRegion *mr, bool enabled); /* * memory_region_set_address: dynamically update the address of a region * - * Dynamically updates the address of a region, relative to its parent. + * Dynamically updates the address of a region, relative to its container. * May be used on regions are currently part of a memory hierarchy. * * @mr: the region to be updated - * @addr: new address, relative to parent region + * @addr: new address, relative to container region */ void memory_region_set_address(MemoryRegion *mr, hwaddr addr); @@ -836,16 +836,16 @@ void memory_region_set_alias_offset(MemoryRegion *mr, hwaddr offset); /** - * memory_region_present: checks if an address relative to a @parent - * translates into #MemoryRegion within @parent + * memory_region_present: checks if an address relative to a @container + * translates into #MemoryRegion within @container * - * Answer whether a #MemoryRegion within @parent covers the address + * Answer whether a #MemoryRegion within @container covers the address * @addr. * - * @parent: a #MemoryRegion within which @addr is a relative address - * @addr: the area within @parent to be searched + * @container: a #MemoryRegion within which @addr is a relative address + * @addr: the area within @container to be searched */ -bool memory_region_present(MemoryRegion *parent, hwaddr addr); +bool memory_region_present(MemoryRegion *container, hwaddr addr); /** * memory_region_find: translate an address/size relative to a @@ -866,7 +866,7 @@ bool memory_region_present(MemoryRegion *parent, hwaddr addr); * Similarly, the .@offset_within_address_space is relative to the * address space that contains both regions, the passed and the * returned one. However, in the special case where the @mr argument - * has no parent (and thus is the root of the address space), the + * has no container (and thus is the root of the address space), the * following will hold: * .@offset_within_address_space >= @addr * .@offset_within_address_space + .@size <= @addr + @size diff --git a/memory.c b/memory.c index 678661e2bb3db2fb269ba13e3aca3415425ac14e..4895e253765640d104d85148727c9471d237e94e 100644 --- a/memory.c +++ b/memory.c @@ -28,6 +28,7 @@ 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,8 +485,8 @@ 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) { @@ -786,22 +787,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 +850,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(); @@ -1319,6 +1332,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 +1341,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 +1391,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 +1424,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 +1470,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 +1503,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 +1522,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,10 +1583,10 @@ 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); @@ -1580,8 +1604,8 @@ 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; } diff --git a/savevm.c b/savevm.c index da8aa2428d480ad49cdd5184500d98ba1d1c3f5d..7b2c410ea11927c74af866e7fb8b70f2327afadf 100644 --- a/savevm.c +++ b/savevm.c @@ -1209,7 +1209,7 @@ void vmstate_register_ram(MemoryRegion *mr, DeviceState *dev) void vmstate_unregister_ram(MemoryRegion *mr, DeviceState *dev) { - /* Nothing do to while the implementation is in RAMBlock */ + qemu_ram_unset_idstr(memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK); } void vmstate_register_ram_global(MemoryRegion *mr)