#include "kvm.h"
#include <assert.h>
-#define WANT_EXEC_OBSOLETE
-#include "exec-obsolete.h"
+#include "memory-internal.h"
unsigned memory_region_transaction_depth = 0;
-static bool memory_region_update_pending = false;
static bool global_dirty_log = false;
static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners
= QTAILQ_HEAD_INITIALIZER(memory_listeners);
+static QTAILQ_HEAD(, AddressSpace) address_spaces
+ = QTAILQ_HEAD_INITIALIZER(address_spaces);
+
typedef struct AddrRange AddrRange;
/*
unsigned nr_allocated;
};
-typedef struct AddressSpace AddressSpace;
typedef struct AddressSpaceOps AddressSpaceOps;
-/* A system address space - I/O, memory, etc. */
-struct AddressSpace {
- MemoryRegion *root;
- FlatView current_map;
- int ioeventfd_nb;
- MemoryRegionIoeventfd *ioeventfds;
-};
-
#define FOR_EACH_FLAT_RANGE(var, view) \
for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var)
MemoryRegion *mr = opaque;
uint64_t tmp;
+ if (mr->flush_coalesced_mmio) {
+ qemu_flush_coalesced_mmio_buffer();
+ }
tmp = mr->ops->read(mr->opaque, addr, size);
*value |= (tmp & mask) << shift;
}
MemoryRegion *mr = opaque;
uint64_t tmp;
+ if (mr->flush_coalesced_mmio) {
+ qemu_flush_coalesced_mmio_buffer();
+ }
tmp = (*value >> shift) & mask;
mr->ops->write(mr->opaque, addr, tmp, size);
}
static AddressSpace *memory_region_to_address_space(MemoryRegion *mr)
{
+ AddressSpace *as;
+
while (mr->parent) {
mr = mr->parent;
}
- if (mr == address_space_memory.root) {
- return &address_space_memory;
- }
- if (mr == address_space_io.root) {
- return &address_space_io;
+ QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+ if (mr == as->root) {
+ return as;
+ }
}
abort();
}
AddrRange tmp;
unsigned i;
- FOR_EACH_FLAT_RANGE(fr, &as->current_map) {
+ FOR_EACH_FLAT_RANGE(fr, as->current_map) {
for (i = 0; i < fr->mr->ioeventfd_nb; ++i) {
tmp = addrrange_shift(fr->mr->ioeventfds[i].addr,
int128_sub(fr->addr.start,
static void address_space_update_topology(AddressSpace *as)
{
- FlatView old_view = as->current_map;
+ FlatView old_view = *as->current_map;
FlatView new_view = generate_memory_topology(as->root);
address_space_update_topology_pass(as, old_view, new_view, false);
address_space_update_topology_pass(as, old_view, new_view, true);
- as->current_map = new_view;
+ *as->current_map = new_view;
flatview_destroy(&old_view);
address_space_update_ioeventfds(as);
}
-static void memory_region_update_topology(MemoryRegion *mr)
-{
- if (memory_region_transaction_depth) {
- memory_region_update_pending |= !mr || mr->enabled;
- return;
- }
-
- if (mr && !mr->enabled) {
- return;
- }
-
- MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
-
- if (address_space_memory.root) {
- address_space_update_topology(&address_space_memory);
- }
- if (address_space_io.root) {
- address_space_update_topology(&address_space_io);
- }
-
- MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
-
- memory_region_update_pending = false;
-}
-
void memory_region_transaction_begin(void)
{
+ qemu_flush_coalesced_mmio_buffer();
++memory_region_transaction_depth;
}
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_topology(NULL);
+ if (!memory_region_transaction_depth) {
+ MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
+
+ QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+ address_space_update_topology(as);
+ }
+
+ MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
}
}
mr->dirty_log_mask = 0;
mr->ioeventfd_nb = 0;
mr->ioeventfds = NULL;
+ mr->flush_coalesced_mmio = false;
}
static bool memory_region_access_valid(MemoryRegion *mr,
{
uint8_t mask = 1 << client;
+ memory_region_transaction_begin();
mr->dirty_log_mask = (mr->dirty_log_mask & ~mask) | (log * mask);
- memory_region_update_topology(mr);
+ memory_region_transaction_commit();
}
bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
{
+ AddressSpace *as;
FlatRange *fr;
- FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
- if (fr->mr == mr) {
- MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory,
- Forward, log_sync);
+ QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+ FOR_EACH_FLAT_RANGE(fr, as->current_map) {
+ if (fr->mr == mr) {
+ MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync);
+ }
}
}
}
void memory_region_set_readonly(MemoryRegion *mr, bool readonly)
{
if (mr->readonly != readonly) {
+ memory_region_transaction_begin();
mr->readonly = readonly;
- memory_region_update_topology(mr);
+ memory_region_transaction_commit();
}
}
void memory_region_rom_device_set_readable(MemoryRegion *mr, bool readable)
{
if (mr->readable != readable) {
+ memory_region_transaction_begin();
mr->readable = readable;
- memory_region_update_topology(mr);
+ memory_region_transaction_commit();
}
}
return qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK);
}
-static void memory_region_update_coalesced_range(MemoryRegion *mr)
+static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpace *as)
{
FlatRange *fr;
CoalescedMemoryRange *cmr;
AddrRange tmp;
- FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
+ FOR_EACH_FLAT_RANGE(fr, as->current_map) {
if (fr->mr == mr) {
qemu_unregister_coalesced_mmio(int128_get64(fr->addr.start),
int128_get64(fr->addr.size));
}
}
+static void memory_region_update_coalesced_range(MemoryRegion *mr)
+{
+ AddressSpace *as;
+
+ QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+ memory_region_update_coalesced_range_as(mr, as);
+ }
+}
+
void memory_region_set_coalescing(MemoryRegion *mr)
{
memory_region_clear_coalescing(mr);
cmr->addr = addrrange_make(int128_make64(offset), int128_make64(size));
QTAILQ_INSERT_TAIL(&mr->coalesced, cmr, link);
memory_region_update_coalesced_range(mr);
+ memory_region_set_flush_coalesced(mr);
}
void memory_region_clear_coalescing(MemoryRegion *mr)
{
CoalescedMemoryRange *cmr;
+ qemu_flush_coalesced_mmio_buffer();
+ mr->flush_coalesced_mmio = false;
+
while (!QTAILQ_EMPTY(&mr->coalesced)) {
cmr = QTAILQ_FIRST(&mr->coalesced);
QTAILQ_REMOVE(&mr->coalesced, cmr, link);
memory_region_update_coalesced_range(mr);
}
+void memory_region_set_flush_coalesced(MemoryRegion *mr)
+{
+ mr->flush_coalesced_mmio = true;
+}
+
+void memory_region_clear_flush_coalesced(MemoryRegion *mr)
+{
+ qemu_flush_coalesced_mmio_buffer();
+ if (QTAILQ_EMPTY(&mr->coalesced)) {
+ mr->flush_coalesced_mmio = false;
+ }
+}
+
void memory_region_add_eventfd(MemoryRegion *mr,
target_phys_addr_t addr,
unsigned size,
};
unsigned i;
+ memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
if (memory_region_ioeventfd_before(mrfd, mr->ioeventfds[i])) {
break;
memmove(&mr->ioeventfds[i+1], &mr->ioeventfds[i],
sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb-1 - i));
mr->ioeventfds[i] = mrfd;
- memory_region_update_topology(mr);
+ memory_region_transaction_commit();
}
void memory_region_del_eventfd(MemoryRegion *mr,
};
unsigned i;
+ memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
if (memory_region_ioeventfd_equal(mrfd, mr->ioeventfds[i])) {
break;
--mr->ioeventfd_nb;
mr->ioeventfds = g_realloc(mr->ioeventfds,
sizeof(*mr->ioeventfds)*mr->ioeventfd_nb + 1);
- memory_region_update_topology(mr);
+ memory_region_transaction_commit();
}
static void memory_region_add_subregion_common(MemoryRegion *mr,
{
MemoryRegion *other;
+ memory_region_transaction_begin();
+
assert(!subregion->parent);
subregion->parent = mr;
subregion->addr = offset;
}
QTAILQ_INSERT_TAIL(&mr->subregions, subregion, subregions_link);
done:
- memory_region_update_topology(mr);
+ memory_region_transaction_commit();
}
void memory_region_del_subregion(MemoryRegion *mr,
MemoryRegion *subregion)
{
+ memory_region_transaction_begin();
assert(subregion->parent == mr);
subregion->parent = NULL;
QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link);
- memory_region_update_topology(mr);
+ memory_region_transaction_commit();
}
void memory_region_set_enabled(MemoryRegion *mr, bool enabled)
if (enabled == mr->enabled) {
return;
}
+ memory_region_transaction_begin();
mr->enabled = enabled;
- memory_region_update_topology(NULL);
+ memory_region_transaction_commit();
}
void memory_region_set_address(MemoryRegion *mr, target_phys_addr_t addr)
void memory_region_set_alias_offset(MemoryRegion *mr, target_phys_addr_t offset)
{
- target_phys_addr_t old_offset = mr->alias_offset;
-
assert(mr->alias);
- mr->alias_offset = offset;
- if (offset == old_offset || !mr->parent) {
+ if (offset == mr->alias_offset) {
return;
}
- memory_region_update_topology(mr);
+ memory_region_transaction_begin();
+ mr->alias_offset = offset;
+ memory_region_transaction_commit();
}
ram_addr_t memory_region_get_ram_addr(MemoryRegion *mr)
static FlatRange *address_space_lookup(AddressSpace *as, AddrRange addr)
{
- return bsearch(&addr, as->current_map.ranges, as->current_map.nr,
+ return bsearch(&addr, as->current_map->ranges, as->current_map->nr,
sizeof(FlatRange), cmp_flatrange_addr);
}
return ret;
}
- while (fr > as->current_map.ranges
+ while (fr > as->current_map->ranges
&& addrrange_intersects(fr[-1].addr, range)) {
--fr;
}
AddressSpace *as = memory_region_to_address_space(address_space);
FlatRange *fr;
- FOR_EACH_FLAT_RANGE(fr, &as->current_map) {
+ FOR_EACH_FLAT_RANGE(fr, as->current_map) {
MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync);
}
}
if (global_dirty_log) {
listener->log_global_start(listener);
}
- FOR_EACH_FLAT_RANGE(fr, &as->current_map) {
+ FOR_EACH_FLAT_RANGE(fr, as->current_map) {
MemoryRegionSection section = {
.mr = fr->mr,
.address_space = as->root,
void memory_listener_register(MemoryListener *listener, MemoryRegion *filter)
{
MemoryListener *other = NULL;
+ AddressSpace *as;
listener->address_space_filter = filter;
if (QTAILQ_EMPTY(&memory_listeners)
}
QTAILQ_INSERT_BEFORE(other, listener, link);
}
- listener_add_address_space(listener, &address_space_memory);
- listener_add_address_space(listener, &address_space_io);
+
+ QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+ listener_add_address_space(listener, as);
+ }
}
void memory_listener_unregister(MemoryListener *listener)
QTAILQ_REMOVE(&memory_listeners, listener, link);
}
+void address_space_init(AddressSpace *as, MemoryRegion *root)
+{
+ memory_region_transaction_begin();
+ as->root = root;
+ as->current_map = g_new(FlatView, 1);
+ flatview_init(as->current_map);
+ QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
+ as->name = NULL;
+ memory_region_transaction_commit();
+}
+
void set_system_memory_map(MemoryRegion *mr)
{
- address_space_memory.root = mr;
- memory_region_update_topology(NULL);
+ address_space_init(&address_space_memory, mr);
+ address_space_memory.name = "memory";
}
void set_system_io_map(MemoryRegion *mr)
{
- address_space_io.root = mr;
- memory_region_update_topology(NULL);
+ address_space_init(&address_space_io, mr);
+ address_space_io.name = "I/O";
}
uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size)
{
MemoryRegionListHead ml_head;
MemoryRegionList *ml, *ml2;
+ AddressSpace *as;
QTAILQ_INIT(&ml_head);
- mon_printf(f, "memory\n");
- mtree_print_mr(mon_printf, f, address_space_memory.root, 0, 0, &ml_head);
-
- if (address_space_io.root &&
- !QTAILQ_EMPTY(&address_space_io.root->subregions)) {
- mon_printf(f, "I/O\n");
- mtree_print_mr(mon_printf, f, address_space_io.root, 0, 0, &ml_head);
+ QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+ if (!as->name) {
+ continue;
+ }
+ mon_printf(f, "%s\n", as->name);
+ mtree_print_mr(mon_printf, f, as->root, 0, 0, &ml_head);
}
mon_printf(f, "aliases\n");