X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=memory.c;h=ed8b5aa83ee7300a6139f8df4d6ef899196d891e;hb=0aeebc73b7976bae5cb7e9768e3d9a0fd9d634e8;hp=27a3f2fca286a6810ea1eb9d4b8f0336b3265dc5;hpb=5bf3d319030b1e95116ba49b31339f2bdd1d3b2a;p=mirror_qemu.git diff --git a/memory.c b/memory.c index 27a3f2fca2..ed8b5aa83e 100644 --- a/memory.c +++ b/memory.c @@ -24,7 +24,7 @@ #include "qemu/bitops.h" #include "qemu/error-report.h" #include "qom/object.h" -#include "trace.h" +#include "trace-root.h" #include "exec/memory-internal.h" #include "exec/ram_addr.h" @@ -97,13 +97,6 @@ static AddrRange addrrange_intersection(AddrRange r1, AddrRange r2) enum ListenerDirection { Forward, Reverse }; -static bool memory_listener_match(MemoryListener *listener, - MemoryRegionSection *section) -{ - return !listener->address_space_filter - || listener->address_space_filter == section->address_space; -} - #define MEMORY_LISTENER_CALL_GLOBAL(_callback, _direction, _args...) \ do { \ MemoryListener *_listener; \ @@ -129,24 +122,23 @@ static bool memory_listener_match(MemoryListener *listener, } \ } while (0) -#define MEMORY_LISTENER_CALL(_callback, _direction, _section, _args...) \ +#define MEMORY_LISTENER_CALL(_as, _callback, _direction, _section, _args...) \ do { \ MemoryListener *_listener; \ + struct memory_listeners_as *list = &(_as)->listeners; \ \ switch (_direction) { \ case Forward: \ - QTAILQ_FOREACH(_listener, &memory_listeners, link) { \ - if (_listener->_callback \ - && memory_listener_match(_listener, _section)) { \ + QTAILQ_FOREACH(_listener, list, link_as) { \ + if (_listener->_callback) { \ _listener->_callback(_listener, _section, ##_args); \ } \ } \ break; \ case Reverse: \ - QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \ - memory_listeners, link) { \ - if (_listener->_callback \ - && memory_listener_match(_listener, _section)) { \ + QTAILQ_FOREACH_REVERSE(_listener, list, memory_listeners_as, \ + link_as) { \ + if (_listener->_callback) { \ _listener->_callback(_listener, _section, ##_args); \ } \ } \ @@ -158,14 +150,10 @@ static bool memory_listener_match(MemoryListener *listener, /* No need to ref/unref .mr, the FlatRange keeps it alive. */ #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback, _args...) \ - MEMORY_LISTENER_CALL(callback, dir, (&(MemoryRegionSection) { \ - .mr = (fr)->mr, \ - .address_space = (as), \ - .offset_within_region = (fr)->offset_in_region, \ - .size = (fr)->addr.size, \ - .offset_within_address_space = int128_get64((fr)->addr.start), \ - .readonly = (fr)->readonly, \ - }), ##_args) + do { \ + MemoryRegionSection mrs = section_from_flat_range(fr, as); \ + MEMORY_LISTENER_CALL(as, callback, dir, &mrs, ##_args); \ + } while(0) struct CoalescedMemoryRange { AddrRange addr; @@ -245,6 +233,19 @@ typedef struct AddressSpaceOps AddressSpaceOps; #define FOR_EACH_FLAT_RANGE(var, view) \ for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var) +static inline MemoryRegionSection +section_from_flat_range(FlatRange *fr, AddressSpace *as) +{ + return (MemoryRegionSection) { + .mr = fr->mr, + .address_space = as, + .offset_within_region = fr->offset_in_region, + .size = fr->addr.size, + .offset_within_address_space = int128_get64(fr->addr.start), + .readonly = fr->readonly, + }; +} + static bool flatrange_equal(FlatRange *a, FlatRange *b) { return a->mr == b->mr @@ -740,7 +741,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as, .offset_within_address_space = int128_get64(fd->addr.start), .size = fd->addr.size, }; - MEMORY_LISTENER_CALL(eventfd_del, Forward, §ion, + MEMORY_LISTENER_CALL(as, eventfd_del, Forward, §ion, fd->match_data, fd->data, fd->e); ++iold; } else if (inew < fds_new_nb @@ -753,7 +754,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as, .offset_within_address_space = int128_get64(fd->addr.start), .size = fd->addr.size, }; - MEMORY_LISTENER_CALL(eventfd_add, Reverse, §ion, + MEMORY_LISTENER_CALL(as, eventfd_add, Reverse, §ion, fd->match_data, fd->data, fd->e); ++inew; } else { @@ -1127,6 +1128,71 @@ const MemoryRegionOps unassigned_mem_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +static uint64_t memory_region_ram_device_read(void *opaque, + hwaddr addr, unsigned size) +{ + MemoryRegion *mr = opaque; + uint64_t data = (uint64_t)~0; + + switch (size) { + case 1: + data = *(uint8_t *)(mr->ram_block->host + addr); + break; + case 2: + data = *(uint16_t *)(mr->ram_block->host + addr); + break; + case 4: + data = *(uint32_t *)(mr->ram_block->host + addr); + break; + case 8: + data = *(uint64_t *)(mr->ram_block->host + addr); + break; + } + + trace_memory_region_ram_device_read(get_cpu_index(), mr, addr, data, size); + + return data; +} + +static void memory_region_ram_device_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + MemoryRegion *mr = opaque; + + trace_memory_region_ram_device_write(get_cpu_index(), mr, addr, data, size); + + switch (size) { + case 1: + *(uint8_t *)(mr->ram_block->host + addr) = (uint8_t)data; + break; + case 2: + *(uint16_t *)(mr->ram_block->host + addr) = (uint16_t)data; + break; + case 4: + *(uint32_t *)(mr->ram_block->host + addr) = (uint32_t)data; + break; + case 8: + *(uint64_t *)(mr->ram_block->host + addr) = data; + break; + } +} + +static const MemoryRegionOps ram_device_mem_ops = { + .read = memory_region_ram_device_read, + .write = memory_region_ram_device_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = true, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = true, + }, +}; + bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, unsigned size, @@ -1354,9 +1420,16 @@ void memory_region_init_ram_ptr(MemoryRegion *mr, mr->ram_block = qemu_ram_alloc_from_ptr(size, ptr, mr, &error_fatal); } -void memory_region_set_skip_dump(MemoryRegion *mr) +void memory_region_init_ram_device_ptr(MemoryRegion *mr, + Object *owner, + const char *name, + uint64_t size, + void *ptr) { - mr->skip_dump = true; + memory_region_init_ram_ptr(mr, owner, name, size, ptr); + mr->ram_device = true; + mr->ops = &ram_device_mem_ops; + mr->opaque = mr; } void memory_region_init_alias(MemoryRegion *mr, @@ -1490,15 +1563,15 @@ const char *memory_region_name(const MemoryRegion *mr) return mr->name; } -bool memory_region_is_skip_dump(MemoryRegion *mr) +bool memory_region_is_ram_device(MemoryRegion *mr) { - return mr->skip_dump; + return mr->ram_device; } uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr) { uint8_t mask = mr->dirty_log_mask; - if (global_dirty_log) { + if (global_dirty_log && mr->ram_block) { mask |= (1 << DIRTY_MEMORY_MIGRATION); } return mask; @@ -1530,6 +1603,11 @@ static void memory_region_update_iommu_notify_flags(MemoryRegion *mr) void memory_region_register_iommu_notifier(MemoryRegion *mr, IOMMUNotifier *n) { + if (mr->alias) { + memory_region_register_iommu_notifier(mr->alias, n); + return; + } + /* We need to register for at least one bitfield */ assert(n->notifier_flags != IOMMU_NOTIFIER_NONE); QLIST_INSERT_HEAD(&mr->iommu_notify, n, node); @@ -1570,6 +1648,10 @@ void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n, void memory_region_unregister_iommu_notifier(MemoryRegion *mr, IOMMUNotifier *n) { + if (mr->alias) { + memory_region_unregister_iommu_notifier(mr->alias, n); + return; + } QLIST_REMOVE(n, node); memory_region_update_iommu_notify_flags(mr); } @@ -1641,14 +1723,26 @@ bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr, void memory_region_sync_dirty_bitmap(MemoryRegion *mr) { + MemoryListener *listener; AddressSpace *as; + FlatView *view; FlatRange *fr; - QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { - FlatView *view = address_space_get_flatview(as); + /* If the same address space has multiple log_sync listeners, we + * visit that address space's FlatView multiple times. But because + * log_sync listeners are rare, it's still cheaper than walking each + * address space once. + */ + QTAILQ_FOREACH(listener, &memory_listeners, link) { + if (!listener->log_sync) { + continue; + } + as = listener->address_space; + view = address_space_get_flatview(as); FOR_EACH_FLAT_RANGE(fr, view) { if (fr->mr == mr) { - MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync); + MemoryRegionSection mrs = section_from_flat_range(fr, as); + listener->log_sync(listener, &mrs); } } flatview_unref(view); @@ -1765,7 +1859,7 @@ static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpa .size = fr->addr.size, }; - MEMORY_LISTENER_CALL(coalesced_mmio_del, Reverse, §ion, + MEMORY_LISTENER_CALL(as, coalesced_mmio_del, Reverse, §ion, int128_get64(fr->addr.start), int128_get64(fr->addr.size)); QTAILQ_FOREACH(cmr, &mr->coalesced, link) { @@ -1776,7 +1870,7 @@ static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpa continue; } tmp = addrrange_intersection(tmp, fr->addr); - MEMORY_LISTENER_CALL(coalesced_mmio_add, Forward, §ion, + MEMORY_LISTENER_CALL(as, coalesced_mmio_add, Forward, §ion, int128_get64(tmp.start), int128_get64(tmp.size)); } @@ -2156,16 +2250,27 @@ bool memory_region_present(MemoryRegion *container, hwaddr addr) return mr && mr != container; } -void address_space_sync_dirty_bitmap(AddressSpace *as) +void memory_global_dirty_log_sync(void) { + MemoryListener *listener; + AddressSpace *as; FlatView *view; FlatRange *fr; - view = address_space_get_flatview(as); - FOR_EACH_FLAT_RANGE(fr, view) { - MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync); + QTAILQ_FOREACH(listener, &memory_listeners, link) { + if (!listener->log_sync) { + continue; + } + as = listener->address_space; + view = address_space_get_flatview(as); + FOR_EACH_FLAT_RANGE(fr, view) { + if (fr->dirty_log_mask) { + MemoryRegionSection mrs = section_from_flat_range(fr, as); + listener->log_sync(listener, &mrs); + } + } + flatview_unref(view); } - flatview_unref(view); } void memory_global_dirty_log_start(void) @@ -2198,11 +2303,6 @@ static void listener_add_address_space(MemoryListener *listener, FlatView *view; FlatRange *fr; - if (listener->address_space_filter - && listener->address_space_filter != as) { - return; - } - if (listener->begin) { listener->begin(listener); } @@ -2235,12 +2335,11 @@ static void listener_add_address_space(MemoryListener *listener, flatview_unref(view); } -void memory_listener_register(MemoryListener *listener, AddressSpace *filter) +void memory_listener_register(MemoryListener *listener, AddressSpace *as) { MemoryListener *other = NULL; - AddressSpace *as; - listener->address_space_filter = filter; + listener->address_space = as; if (QTAILQ_EMPTY(&memory_listeners) || listener->priority >= QTAILQ_LAST(&memory_listeners, memory_listeners)->priority) { @@ -2254,14 +2353,31 @@ void memory_listener_register(MemoryListener *listener, AddressSpace *filter) QTAILQ_INSERT_BEFORE(other, listener, link); } - QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { - listener_add_address_space(listener, as); + if (QTAILQ_EMPTY(&as->listeners) + || listener->priority >= QTAILQ_LAST(&as->listeners, + memory_listeners)->priority) { + QTAILQ_INSERT_TAIL(&as->listeners, listener, link_as); + } else { + QTAILQ_FOREACH(other, &as->listeners, link_as) { + if (listener->priority < other->priority) { + break; + } + } + QTAILQ_INSERT_BEFORE(other, listener, link_as); } + + listener_add_address_space(listener, as); } void memory_listener_unregister(MemoryListener *listener) { + if (!listener->address_space) { + return; + } + QTAILQ_REMOVE(&memory_listeners, listener, link); + QTAILQ_REMOVE(&listener->address_space->listeners, listener, link_as); + listener->address_space = NULL; } void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) @@ -2275,6 +2391,7 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) flatview_init(as->current_map); as->ioeventfd_nb = 0; as->ioeventfds = NULL; + QTAILQ_INIT(&as->listeners); QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link); as->name = g_strdup(name ? name : "anonymous"); address_space_init_dispatch(as); @@ -2284,14 +2401,10 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name) static void do_address_space_destroy(AddressSpace *as) { - MemoryListener *listener; bool do_free = as->malloced; address_space_destroy_dispatch(as); - - QTAILQ_FOREACH(listener, &memory_listeners, link) { - assert(listener->address_space_filter != as); - } + assert(QTAILQ_EMPTY(&as->listeners)); flatview_unref(as->current_map); g_free(as->name); @@ -2342,6 +2455,21 @@ void address_space_destroy(AddressSpace *as) call_rcu(as, do_address_space_destroy, rcu); } +static const char *memory_region_type(MemoryRegion *mr) +{ + if (memory_region_is_ram_device(mr)) { + return "ramd"; + } else if (memory_region_is_romd(mr)) { + return "romd"; + } else if (memory_region_is_rom(mr)) { + return "rom"; + } else if (memory_region_is_ram(mr)) { + return "ram"; + } else { + return "i/o"; + } +} + typedef struct MemoryRegionList MemoryRegionList; struct MemoryRegionList { @@ -2351,6 +2479,10 @@ struct MemoryRegionList { typedef QTAILQ_HEAD(queue, MemoryRegionList) MemoryRegionListHead; +#define MR_SIZE(size) (int128_nz(size) ? (hwaddr)int128_get64( \ + int128_sub((size), int128_one())) : 0) +#define MTREE_INDENT " " + static void mtree_print_mr(fprintf_function mon_printf, void *f, const MemoryRegion *mr, unsigned int level, hwaddr base, @@ -2366,7 +2498,7 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, } for (i = 0; i < level; i++) { - mon_printf(f, " "); + mon_printf(f, MTREE_INDENT); } if (mr->alias) { @@ -2386,37 +2518,24 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, QTAILQ_INSERT_TAIL(alias_print_queue, ml, queue); } mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx - " (prio %d, %c%c): alias %s @%s " TARGET_FMT_plx + " (prio %d, %s): alias %s @%s " TARGET_FMT_plx "-" TARGET_FMT_plx "%s\n", base + mr->addr, - base + mr->addr - + (int128_nz(mr->size) ? - (hwaddr)int128_get64(int128_sub(mr->size, - int128_one())) : 0), + base + mr->addr + MR_SIZE(mr->size), mr->priority, - mr->romd_mode ? 'R' : '-', - !mr->readonly && !(mr->rom_device && mr->romd_mode) ? 'W' - : '-', + memory_region_type((MemoryRegion *)mr), memory_region_name(mr), memory_region_name(mr->alias), mr->alias_offset, - mr->alias_offset - + (int128_nz(mr->size) ? - (hwaddr)int128_get64(int128_sub(mr->size, - int128_one())) : 0), + mr->alias_offset + MR_SIZE(mr->size), mr->enabled ? "" : " [disabled]"); } else { mon_printf(f, - TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %c%c): %s%s\n", + TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %s): %s%s\n", base + mr->addr, - base + mr->addr - + (int128_nz(mr->size) ? - (hwaddr)int128_get64(int128_sub(mr->size, - int128_one())) : 0), + base + mr->addr + MR_SIZE(mr->size), mr->priority, - mr->romd_mode ? 'R' : '-', - !mr->readonly && !(mr->rom_device && mr->romd_mode) ? 'W' - : '-', + memory_region_type((MemoryRegion *)mr), memory_region_name(mr), mr->enabled ? "" : " [disabled]"); } @@ -2450,12 +2569,51 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, } } -void mtree_info(fprintf_function mon_printf, void *f) +static void mtree_print_flatview(fprintf_function p, void *f, + AddressSpace *as) +{ + FlatView *view = address_space_get_flatview(as); + FlatRange *range = &view->ranges[0]; + MemoryRegion *mr; + int n = view->nr; + + if (n <= 0) { + p(f, MTREE_INDENT "No rendered FlatView for " + "address space '%s'\n", as->name); + flatview_unref(view); + return; + } + + while (n--) { + mr = range->mr; + p(f, MTREE_INDENT TARGET_FMT_plx "-" + TARGET_FMT_plx " (prio %d, %s): %s\n", + int128_get64(range->addr.start), + int128_get64(range->addr.start) + MR_SIZE(range->addr.size), + mr->priority, + memory_region_type(mr), + memory_region_name(mr)); + range++; + } + + flatview_unref(view); +} + +void mtree_info(fprintf_function mon_printf, void *f, bool flatview) { MemoryRegionListHead ml_head; MemoryRegionList *ml, *ml2; AddressSpace *as; + if (flatview) { + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + mon_printf(f, "address-space (flat view): %s\n", as->name); + mtree_print_flatview(mon_printf, f, as); + mon_printf(f, "\n"); + } + return; + } + QTAILQ_INIT(&ml_head); QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {