diff options
Diffstat (limited to 'memory.c')
-rw-r--r-- | memory.c | 173 |
1 files changed, 104 insertions, 69 deletions
@@ -20,8 +20,7 @@ #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 global_dirty_log = false; @@ -29,6 +28,9 @@ 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; /* @@ -97,13 +99,17 @@ static bool memory_listener_match(MemoryListener *listener, switch (_direction) { \ case Forward: \ QTAILQ_FOREACH(_listener, &memory_listeners, link) { \ - _listener->_callback(_listener, ##_args); \ + if (_listener->_callback) { \ + _listener->_callback(_listener, ##_args); \ + } \ } \ break; \ case Reverse: \ QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \ memory_listeners, link) { \ - _listener->_callback(_listener, ##_args); \ + if (_listener->_callback) { \ + _listener->_callback(_listener, ##_args); \ + } \ } \ break; \ default: \ @@ -118,7 +124,8 @@ static bool memory_listener_match(MemoryListener *listener, switch (_direction) { \ case Forward: \ QTAILQ_FOREACH(_listener, &memory_listeners, link) { \ - if (memory_listener_match(_listener, _section)) { \ + if (_listener->_callback \ + && memory_listener_match(_listener, _section)) { \ _listener->_callback(_listener, _section, ##_args); \ } \ } \ @@ -126,7 +133,8 @@ static bool memory_listener_match(MemoryListener *listener, case Reverse: \ QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \ memory_listeners, link) { \ - if (memory_listener_match(_listener, _section)) { \ + if (_listener->_callback \ + && memory_listener_match(_listener, _section)) { \ _listener->_callback(_listener, _section, ##_args); \ } \ } \ @@ -139,7 +147,7 @@ static bool memory_listener_match(MemoryListener *listener, #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback) \ MEMORY_LISTENER_CALL(callback, dir, (&(MemoryRegionSection) { \ .mr = (fr)->mr, \ - .address_space = (as)->root, \ + .address_space = (as), \ .offset_within_region = (fr)->offset_in_region, \ .size = int128_get64((fr)->addr.size), \ .offset_within_address_space = int128_get64((fr)->addr.start), \ @@ -217,17 +225,8 @@ struct FlatView { 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) @@ -365,8 +364,6 @@ static void access_with_adjusted_size(target_phys_addr_t addr, } } -static AddressSpace address_space_memory; - static const MemoryRegionPortio *find_portio(MemoryRegion *mr, uint64_t offset, unsigned width, bool write) { @@ -455,18 +452,17 @@ const IORangeOps memory_region_iorange_ops = { .destructor = memory_region_iorange_destructor, }; -static AddressSpace address_space_io; - 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(); } @@ -568,8 +564,10 @@ static FlatView generate_memory_topology(MemoryRegion *mr) flatview_init(&view); - render_memory_region(&view, mr, int128_zero(), - addrrange_make(int128_zero(), int128_2_64()), false); + if (mr) { + render_memory_region(&view, mr, int128_zero(), + addrrange_make(int128_zero(), int128_2_64()), false); + } flatview_simplify(&view); return view; @@ -597,7 +595,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as, fds_new[inew]))) { fd = &fds_old[iold]; section = (MemoryRegionSection) { - .address_space = as->root, + .address_space = as, .offset_within_address_space = int128_get64(fd->addr.start), .size = int128_get64(fd->addr.size), }; @@ -610,7 +608,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as, fds_old[iold]))) { fd = &fds_new[inew]; section = (MemoryRegionSection) { - .address_space = as->root, + .address_space = as, .offset_within_address_space = int128_get64(fd->addr.start), .size = int128_get64(fd->addr.size), }; @@ -632,7 +630,7 @@ static void address_space_update_ioeventfds(AddressSpace *as) 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, @@ -720,13 +718,13 @@ static void address_space_update_topology_pass(AddressSpace *as, 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); } @@ -739,16 +737,15 @@ void memory_region_transaction_begin(void) void memory_region_transaction_commit(void) { + AddressSpace *as; + assert(memory_region_transaction_depth); --memory_region_transaction_depth; if (!memory_region_transaction_depth) { 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); + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + address_space_update_topology(as); } MEMORY_LISTENER_CALL_GLOBAL(commit, Forward); @@ -1082,12 +1079,14 @@ void memory_region_set_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); + } } } } @@ -1130,16 +1129,24 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr) 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; + MemoryRegionSection section; - 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)); + section = (MemoryRegionSection) { + .address_space = as, + .offset_within_address_space = int128_get64(fr->addr.start), + .size = int128_get64(fr->addr.size), + }; + + MEMORY_LISTENER_CALL(coalesced_mmio_del, Reverse, §ion, + int128_get64(fr->addr.start), + int128_get64(fr->addr.size)); QTAILQ_FOREACH(cmr, &mr->coalesced, link) { tmp = addrrange_shift(cmr->addr, int128_sub(fr->addr.start, @@ -1148,13 +1155,23 @@ static void memory_region_update_coalesced_range(MemoryRegion *mr) continue; } tmp = addrrange_intersection(tmp, fr->addr); - qemu_register_coalesced_mmio(int128_get64(tmp.start), - int128_get64(tmp.size)); + MEMORY_LISTENER_CALL(coalesced_mmio_add, Forward, §ion, + int128_get64(tmp.start), + int128_get64(tmp.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); @@ -1400,7 +1417,7 @@ static int cmp_flatrange_addr(const void *addr_, const void *fr_) 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); } @@ -1417,7 +1434,7 @@ MemoryRegionSection memory_region_find(MemoryRegion *address_space, return ret; } - while (fr > as->current_map.ranges + while (fr > as->current_map->ranges && addrrange_intersects(fr[-1].addr, range)) { --fr; } @@ -1438,7 +1455,7 @@ void memory_global_sync_dirty_bitmap(MemoryRegion *address_space) 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); } } @@ -1461,29 +1478,35 @@ static void listener_add_address_space(MemoryListener *listener, FlatRange *fr; if (listener->address_space_filter - && listener->address_space_filter != as->root) { + && listener->address_space_filter != as) { return; } if (global_dirty_log) { - listener->log_global_start(listener); + if (listener->log_global_start) { + 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, + .address_space = as, .offset_within_region = fr->offset_in_region, .size = int128_get64(fr->addr.size), .offset_within_address_space = int128_get64(fr->addr.start), .readonly = fr->readonly, }; - listener->region_add(listener, §ion); + if (listener->region_add) { + listener->region_add(listener, §ion); + } } } -void memory_listener_register(MemoryListener *listener, MemoryRegion *filter) +void memory_listener_register(MemoryListener *listener, AddressSpace *filter) { MemoryListener *other = NULL; + AddressSpace *as; listener->address_space_filter = filter; if (QTAILQ_EMPTY(&memory_listeners) @@ -1498,8 +1521,10 @@ void memory_listener_register(MemoryListener *listener, MemoryRegion *filter) } 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) @@ -1507,18 +1532,28 @@ void memory_listener_unregister(MemoryListener *listener) QTAILQ_REMOVE(&memory_listeners, listener, link); } -void set_system_memory_map(MemoryRegion *mr) +void address_space_init(AddressSpace *as, MemoryRegion *root) { memory_region_transaction_begin(); - address_space_memory.root = mr; + 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(); + address_space_init_dispatch(as); } -void set_system_io_map(MemoryRegion *mr) +void address_space_destroy(AddressSpace *as) { + /* Flush out anything from MemoryListeners listening in on this */ memory_region_transaction_begin(); - address_space_io.root = mr; + as->root = NULL; memory_region_transaction_commit(); + QTAILQ_REMOVE(&address_spaces, as, address_spaces_link); + address_space_destroy_dispatch(as); + flatview_destroy(as->current_map); + g_free(as->current_map); } uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size) @@ -1638,16 +1673,16 @@ void mtree_info(fprintf_function mon_printf, void *f) { 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"); |