xref: /openbmc/qemu/system/memory.c (revision 557e1d67c4ddc9f83e367a28795f02be40440a63)
18d7f2e76SPhilippe Mathieu-Daudé /*
28d7f2e76SPhilippe Mathieu-Daudé  * Physical memory management
38d7f2e76SPhilippe Mathieu-Daudé  *
48d7f2e76SPhilippe Mathieu-Daudé  * Copyright 2011 Red Hat, Inc. and/or its affiliates
58d7f2e76SPhilippe Mathieu-Daudé  *
68d7f2e76SPhilippe Mathieu-Daudé  * Authors:
78d7f2e76SPhilippe Mathieu-Daudé  *  Avi Kivity <avi@redhat.com>
88d7f2e76SPhilippe Mathieu-Daudé  *
98d7f2e76SPhilippe Mathieu-Daudé  * This work is licensed under the terms of the GNU GPL, version 2.  See
108d7f2e76SPhilippe Mathieu-Daudé  * the COPYING file in the top-level directory.
118d7f2e76SPhilippe Mathieu-Daudé  *
128d7f2e76SPhilippe Mathieu-Daudé  * Contributions after 2012-01-13 are licensed under the terms of the
138d7f2e76SPhilippe Mathieu-Daudé  * GNU GPL, version 2 or (at your option) any later version.
148d7f2e76SPhilippe Mathieu-Daudé  */
158d7f2e76SPhilippe Mathieu-Daudé 
168d7f2e76SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
178d7f2e76SPhilippe Mathieu-Daudé #include "qemu/log.h"
188d7f2e76SPhilippe Mathieu-Daudé #include "qapi/error.h"
198d7f2e76SPhilippe Mathieu-Daudé #include "exec/memory.h"
208d7f2e76SPhilippe Mathieu-Daudé #include "qapi/visitor.h"
218d7f2e76SPhilippe Mathieu-Daudé #include "qemu/bitops.h"
228d7f2e76SPhilippe Mathieu-Daudé #include "qemu/error-report.h"
238d7f2e76SPhilippe Mathieu-Daudé #include "qemu/main-loop.h"
248d7f2e76SPhilippe Mathieu-Daudé #include "qemu/qemu-print.h"
258d7f2e76SPhilippe Mathieu-Daudé #include "qom/object.h"
268d7f2e76SPhilippe Mathieu-Daudé #include "trace.h"
278d7f2e76SPhilippe Mathieu-Daudé 
288d7f2e76SPhilippe Mathieu-Daudé #include "exec/memory-internal.h"
298d7f2e76SPhilippe Mathieu-Daudé #include "exec/ram_addr.h"
308d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/kvm.h"
318d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/runstate.h"
328d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/tcg.h"
338d7f2e76SPhilippe Mathieu-Daudé #include "qemu/accel.h"
348d7f2e76SPhilippe Mathieu-Daudé #include "hw/boards.h"
358d7f2e76SPhilippe Mathieu-Daudé #include "migration/vmstate.h"
368d7f2e76SPhilippe Mathieu-Daudé #include "exec/address-spaces.h"
378d7f2e76SPhilippe Mathieu-Daudé 
388d7f2e76SPhilippe Mathieu-Daudé //#define DEBUG_UNASSIGNED
398d7f2e76SPhilippe Mathieu-Daudé 
408d7f2e76SPhilippe Mathieu-Daudé static unsigned memory_region_transaction_depth;
418d7f2e76SPhilippe Mathieu-Daudé static bool memory_region_update_pending;
428d7f2e76SPhilippe Mathieu-Daudé static bool ioeventfd_update_pending;
438d7f2e76SPhilippe Mathieu-Daudé unsigned int global_dirty_tracking;
448d7f2e76SPhilippe Mathieu-Daudé 
458d7f2e76SPhilippe Mathieu-Daudé static QTAILQ_HEAD(, MemoryListener) memory_listeners
468d7f2e76SPhilippe Mathieu-Daudé     = QTAILQ_HEAD_INITIALIZER(memory_listeners);
478d7f2e76SPhilippe Mathieu-Daudé 
488d7f2e76SPhilippe Mathieu-Daudé static QTAILQ_HEAD(, AddressSpace) address_spaces
498d7f2e76SPhilippe Mathieu-Daudé     = QTAILQ_HEAD_INITIALIZER(address_spaces);
508d7f2e76SPhilippe Mathieu-Daudé 
518d7f2e76SPhilippe Mathieu-Daudé static GHashTable *flat_views;
528d7f2e76SPhilippe Mathieu-Daudé 
538d7f2e76SPhilippe Mathieu-Daudé typedef struct AddrRange AddrRange;
548d7f2e76SPhilippe Mathieu-Daudé 
558d7f2e76SPhilippe Mathieu-Daudé /*
568d7f2e76SPhilippe Mathieu-Daudé  * Note that signed integers are needed for negative offsetting in aliases
578d7f2e76SPhilippe Mathieu-Daudé  * (large MemoryRegion::alias_offset).
588d7f2e76SPhilippe Mathieu-Daudé  */
598d7f2e76SPhilippe Mathieu-Daudé struct AddrRange {
608d7f2e76SPhilippe Mathieu-Daudé     Int128 start;
618d7f2e76SPhilippe Mathieu-Daudé     Int128 size;
628d7f2e76SPhilippe Mathieu-Daudé };
638d7f2e76SPhilippe Mathieu-Daudé 
addrrange_make(Int128 start,Int128 size)648d7f2e76SPhilippe Mathieu-Daudé static AddrRange addrrange_make(Int128 start, Int128 size)
658d7f2e76SPhilippe Mathieu-Daudé {
668d7f2e76SPhilippe Mathieu-Daudé     return (AddrRange) { start, size };
678d7f2e76SPhilippe Mathieu-Daudé }
688d7f2e76SPhilippe Mathieu-Daudé 
addrrange_equal(AddrRange r1,AddrRange r2)698d7f2e76SPhilippe Mathieu-Daudé static bool addrrange_equal(AddrRange r1, AddrRange r2)
708d7f2e76SPhilippe Mathieu-Daudé {
718d7f2e76SPhilippe Mathieu-Daudé     return int128_eq(r1.start, r2.start) && int128_eq(r1.size, r2.size);
728d7f2e76SPhilippe Mathieu-Daudé }
738d7f2e76SPhilippe Mathieu-Daudé 
addrrange_end(AddrRange r)748d7f2e76SPhilippe Mathieu-Daudé static Int128 addrrange_end(AddrRange r)
758d7f2e76SPhilippe Mathieu-Daudé {
768d7f2e76SPhilippe Mathieu-Daudé     return int128_add(r.start, r.size);
778d7f2e76SPhilippe Mathieu-Daudé }
788d7f2e76SPhilippe Mathieu-Daudé 
addrrange_shift(AddrRange range,Int128 delta)798d7f2e76SPhilippe Mathieu-Daudé static AddrRange addrrange_shift(AddrRange range, Int128 delta)
808d7f2e76SPhilippe Mathieu-Daudé {
818d7f2e76SPhilippe Mathieu-Daudé     int128_addto(&range.start, delta);
828d7f2e76SPhilippe Mathieu-Daudé     return range;
838d7f2e76SPhilippe Mathieu-Daudé }
848d7f2e76SPhilippe Mathieu-Daudé 
addrrange_contains(AddrRange range,Int128 addr)858d7f2e76SPhilippe Mathieu-Daudé static bool addrrange_contains(AddrRange range, Int128 addr)
868d7f2e76SPhilippe Mathieu-Daudé {
878d7f2e76SPhilippe Mathieu-Daudé     return int128_ge(addr, range.start)
888d7f2e76SPhilippe Mathieu-Daudé         && int128_lt(addr, addrrange_end(range));
898d7f2e76SPhilippe Mathieu-Daudé }
908d7f2e76SPhilippe Mathieu-Daudé 
addrrange_intersects(AddrRange r1,AddrRange r2)918d7f2e76SPhilippe Mathieu-Daudé static bool addrrange_intersects(AddrRange r1, AddrRange r2)
928d7f2e76SPhilippe Mathieu-Daudé {
938d7f2e76SPhilippe Mathieu-Daudé     return addrrange_contains(r1, r2.start)
948d7f2e76SPhilippe Mathieu-Daudé         || addrrange_contains(r2, r1.start);
958d7f2e76SPhilippe Mathieu-Daudé }
968d7f2e76SPhilippe Mathieu-Daudé 
addrrange_intersection(AddrRange r1,AddrRange r2)978d7f2e76SPhilippe Mathieu-Daudé static AddrRange addrrange_intersection(AddrRange r1, AddrRange r2)
988d7f2e76SPhilippe Mathieu-Daudé {
998d7f2e76SPhilippe Mathieu-Daudé     Int128 start = int128_max(r1.start, r2.start);
1008d7f2e76SPhilippe Mathieu-Daudé     Int128 end = int128_min(addrrange_end(r1), addrrange_end(r2));
1018d7f2e76SPhilippe Mathieu-Daudé     return addrrange_make(start, int128_sub(end, start));
1028d7f2e76SPhilippe Mathieu-Daudé }
1038d7f2e76SPhilippe Mathieu-Daudé 
1048d7f2e76SPhilippe Mathieu-Daudé enum ListenerDirection { Forward, Reverse };
1058d7f2e76SPhilippe Mathieu-Daudé 
1068d7f2e76SPhilippe Mathieu-Daudé #define MEMORY_LISTENER_CALL_GLOBAL(_callback, _direction, _args...)    \
1078d7f2e76SPhilippe Mathieu-Daudé     do {                                                                \
1088d7f2e76SPhilippe Mathieu-Daudé         MemoryListener *_listener;                                      \
1098d7f2e76SPhilippe Mathieu-Daudé                                                                         \
1108d7f2e76SPhilippe Mathieu-Daudé         switch (_direction) {                                           \
1118d7f2e76SPhilippe Mathieu-Daudé         case Forward:                                                   \
1128d7f2e76SPhilippe Mathieu-Daudé             QTAILQ_FOREACH(_listener, &memory_listeners, link) {        \
1138d7f2e76SPhilippe Mathieu-Daudé                 if (_listener->_callback) {                             \
1148d7f2e76SPhilippe Mathieu-Daudé                     _listener->_callback(_listener, ##_args);           \
1158d7f2e76SPhilippe Mathieu-Daudé                 }                                                       \
1168d7f2e76SPhilippe Mathieu-Daudé             }                                                           \
1178d7f2e76SPhilippe Mathieu-Daudé             break;                                                      \
1188d7f2e76SPhilippe Mathieu-Daudé         case Reverse:                                                   \
1198d7f2e76SPhilippe Mathieu-Daudé             QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, link) { \
1208d7f2e76SPhilippe Mathieu-Daudé                 if (_listener->_callback) {                             \
1218d7f2e76SPhilippe Mathieu-Daudé                     _listener->_callback(_listener, ##_args);           \
1228d7f2e76SPhilippe Mathieu-Daudé                 }                                                       \
1238d7f2e76SPhilippe Mathieu-Daudé             }                                                           \
1248d7f2e76SPhilippe Mathieu-Daudé             break;                                                      \
1258d7f2e76SPhilippe Mathieu-Daudé         default:                                                        \
1268d7f2e76SPhilippe Mathieu-Daudé             abort();                                                    \
1278d7f2e76SPhilippe Mathieu-Daudé         }                                                               \
1288d7f2e76SPhilippe Mathieu-Daudé     } while (0)
1298d7f2e76SPhilippe Mathieu-Daudé 
1308d7f2e76SPhilippe Mathieu-Daudé #define MEMORY_LISTENER_CALL(_as, _callback, _direction, _section, _args...) \
1318d7f2e76SPhilippe Mathieu-Daudé     do {                                                                \
1328d7f2e76SPhilippe Mathieu-Daudé         MemoryListener *_listener;                                      \
1338d7f2e76SPhilippe Mathieu-Daudé                                                                         \
1348d7f2e76SPhilippe Mathieu-Daudé         switch (_direction) {                                           \
1358d7f2e76SPhilippe Mathieu-Daudé         case Forward:                                                   \
1368d7f2e76SPhilippe Mathieu-Daudé             QTAILQ_FOREACH(_listener, &(_as)->listeners, link_as) {     \
1378d7f2e76SPhilippe Mathieu-Daudé                 if (_listener->_callback) {                             \
1388d7f2e76SPhilippe Mathieu-Daudé                     _listener->_callback(_listener, _section, ##_args); \
1398d7f2e76SPhilippe Mathieu-Daudé                 }                                                       \
1408d7f2e76SPhilippe Mathieu-Daudé             }                                                           \
1418d7f2e76SPhilippe Mathieu-Daudé             break;                                                      \
1428d7f2e76SPhilippe Mathieu-Daudé         case Reverse:                                                   \
1438d7f2e76SPhilippe Mathieu-Daudé             QTAILQ_FOREACH_REVERSE(_listener, &(_as)->listeners, link_as) { \
1448d7f2e76SPhilippe Mathieu-Daudé                 if (_listener->_callback) {                             \
1458d7f2e76SPhilippe Mathieu-Daudé                     _listener->_callback(_listener, _section, ##_args); \
1468d7f2e76SPhilippe Mathieu-Daudé                 }                                                       \
1478d7f2e76SPhilippe Mathieu-Daudé             }                                                           \
1488d7f2e76SPhilippe Mathieu-Daudé             break;                                                      \
1498d7f2e76SPhilippe Mathieu-Daudé         default:                                                        \
1508d7f2e76SPhilippe Mathieu-Daudé             abort();                                                    \
1518d7f2e76SPhilippe Mathieu-Daudé         }                                                               \
1528d7f2e76SPhilippe Mathieu-Daudé     } while (0)
1538d7f2e76SPhilippe Mathieu-Daudé 
1548d7f2e76SPhilippe Mathieu-Daudé /* No need to ref/unref .mr, the FlatRange keeps it alive.  */
1558d7f2e76SPhilippe Mathieu-Daudé #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback, _args...)  \
1568d7f2e76SPhilippe Mathieu-Daudé     do {                                                                \
1578d7f2e76SPhilippe Mathieu-Daudé         MemoryRegionSection mrs = section_from_flat_range(fr,           \
1588d7f2e76SPhilippe Mathieu-Daudé                 address_space_to_flatview(as));                         \
1598d7f2e76SPhilippe Mathieu-Daudé         MEMORY_LISTENER_CALL(as, callback, dir, &mrs, ##_args);         \
1608d7f2e76SPhilippe Mathieu-Daudé     } while(0)
1618d7f2e76SPhilippe Mathieu-Daudé 
1628d7f2e76SPhilippe Mathieu-Daudé struct CoalescedMemoryRange {
1638d7f2e76SPhilippe Mathieu-Daudé     AddrRange addr;
1648d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_ENTRY(CoalescedMemoryRange) link;
1658d7f2e76SPhilippe Mathieu-Daudé };
1668d7f2e76SPhilippe Mathieu-Daudé 
1678d7f2e76SPhilippe Mathieu-Daudé struct MemoryRegionIoeventfd {
1688d7f2e76SPhilippe Mathieu-Daudé     AddrRange addr;
1698d7f2e76SPhilippe Mathieu-Daudé     bool match_data;
1708d7f2e76SPhilippe Mathieu-Daudé     uint64_t data;
1718d7f2e76SPhilippe Mathieu-Daudé     EventNotifier *e;
1728d7f2e76SPhilippe Mathieu-Daudé };
1738d7f2e76SPhilippe Mathieu-Daudé 
memory_region_ioeventfd_before(MemoryRegionIoeventfd * a,MemoryRegionIoeventfd * b)1748d7f2e76SPhilippe Mathieu-Daudé static bool memory_region_ioeventfd_before(MemoryRegionIoeventfd *a,
1758d7f2e76SPhilippe Mathieu-Daudé                                            MemoryRegionIoeventfd *b)
1768d7f2e76SPhilippe Mathieu-Daudé {
1778d7f2e76SPhilippe Mathieu-Daudé     if (int128_lt(a->addr.start, b->addr.start)) {
1788d7f2e76SPhilippe Mathieu-Daudé         return true;
1798d7f2e76SPhilippe Mathieu-Daudé     } else if (int128_gt(a->addr.start, b->addr.start)) {
1808d7f2e76SPhilippe Mathieu-Daudé         return false;
1818d7f2e76SPhilippe Mathieu-Daudé     } else if (int128_lt(a->addr.size, b->addr.size)) {
1828d7f2e76SPhilippe Mathieu-Daudé         return true;
1838d7f2e76SPhilippe Mathieu-Daudé     } else if (int128_gt(a->addr.size, b->addr.size)) {
1848d7f2e76SPhilippe Mathieu-Daudé         return false;
1858d7f2e76SPhilippe Mathieu-Daudé     } else if (a->match_data < b->match_data) {
1868d7f2e76SPhilippe Mathieu-Daudé         return true;
1878d7f2e76SPhilippe Mathieu-Daudé     } else  if (a->match_data > b->match_data) {
1888d7f2e76SPhilippe Mathieu-Daudé         return false;
1898d7f2e76SPhilippe Mathieu-Daudé     } else if (a->match_data) {
1908d7f2e76SPhilippe Mathieu-Daudé         if (a->data < b->data) {
1918d7f2e76SPhilippe Mathieu-Daudé             return true;
1928d7f2e76SPhilippe Mathieu-Daudé         } else if (a->data > b->data) {
1938d7f2e76SPhilippe Mathieu-Daudé             return false;
1948d7f2e76SPhilippe Mathieu-Daudé         }
1958d7f2e76SPhilippe Mathieu-Daudé     }
1968d7f2e76SPhilippe Mathieu-Daudé     if (a->e < b->e) {
1978d7f2e76SPhilippe Mathieu-Daudé         return true;
1988d7f2e76SPhilippe Mathieu-Daudé     } else if (a->e > b->e) {
1998d7f2e76SPhilippe Mathieu-Daudé         return false;
2008d7f2e76SPhilippe Mathieu-Daudé     }
2018d7f2e76SPhilippe Mathieu-Daudé     return false;
2028d7f2e76SPhilippe Mathieu-Daudé }
2038d7f2e76SPhilippe Mathieu-Daudé 
memory_region_ioeventfd_equal(MemoryRegionIoeventfd * a,MemoryRegionIoeventfd * b)2048d7f2e76SPhilippe Mathieu-Daudé static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd *a,
2058d7f2e76SPhilippe Mathieu-Daudé                                           MemoryRegionIoeventfd *b)
2068d7f2e76SPhilippe Mathieu-Daudé {
2078d7f2e76SPhilippe Mathieu-Daudé     if (int128_eq(a->addr.start, b->addr.start) &&
2088d7f2e76SPhilippe Mathieu-Daudé         (!int128_nz(a->addr.size) || !int128_nz(b->addr.size) ||
2098d7f2e76SPhilippe Mathieu-Daudé          (int128_eq(a->addr.size, b->addr.size) &&
2108d7f2e76SPhilippe Mathieu-Daudé           (a->match_data == b->match_data) &&
2118d7f2e76SPhilippe Mathieu-Daudé           ((a->match_data && (a->data == b->data)) || !a->match_data) &&
2128d7f2e76SPhilippe Mathieu-Daudé           (a->e == b->e))))
2138d7f2e76SPhilippe Mathieu-Daudé         return true;
2148d7f2e76SPhilippe Mathieu-Daudé 
2158d7f2e76SPhilippe Mathieu-Daudé     return false;
2168d7f2e76SPhilippe Mathieu-Daudé }
2178d7f2e76SPhilippe Mathieu-Daudé 
2188d7f2e76SPhilippe Mathieu-Daudé /* Range of memory in the global map.  Addresses are absolute. */
2198d7f2e76SPhilippe Mathieu-Daudé struct FlatRange {
2208d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr;
2218d7f2e76SPhilippe Mathieu-Daudé     hwaddr offset_in_region;
2228d7f2e76SPhilippe Mathieu-Daudé     AddrRange addr;
2238d7f2e76SPhilippe Mathieu-Daudé     uint8_t dirty_log_mask;
2248d7f2e76SPhilippe Mathieu-Daudé     bool romd_mode;
2258d7f2e76SPhilippe Mathieu-Daudé     bool readonly;
2268d7f2e76SPhilippe Mathieu-Daudé     bool nonvolatile;
227533f5d66SDavid Hildenbrand     bool unmergeable;
2288d7f2e76SPhilippe Mathieu-Daudé };
2298d7f2e76SPhilippe Mathieu-Daudé 
2308d7f2e76SPhilippe Mathieu-Daudé #define FOR_EACH_FLAT_RANGE(var, view)          \
2318d7f2e76SPhilippe Mathieu-Daudé     for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var)
2328d7f2e76SPhilippe Mathieu-Daudé 
2338d7f2e76SPhilippe Mathieu-Daudé static inline MemoryRegionSection
section_from_flat_range(FlatRange * fr,FlatView * fv)2348d7f2e76SPhilippe Mathieu-Daudé section_from_flat_range(FlatRange *fr, FlatView *fv)
2358d7f2e76SPhilippe Mathieu-Daudé {
2368d7f2e76SPhilippe Mathieu-Daudé     return (MemoryRegionSection) {
2378d7f2e76SPhilippe Mathieu-Daudé         .mr = fr->mr,
2388d7f2e76SPhilippe Mathieu-Daudé         .fv = fv,
2398d7f2e76SPhilippe Mathieu-Daudé         .offset_within_region = fr->offset_in_region,
2408d7f2e76SPhilippe Mathieu-Daudé         .size = fr->addr.size,
2418d7f2e76SPhilippe Mathieu-Daudé         .offset_within_address_space = int128_get64(fr->addr.start),
2428d7f2e76SPhilippe Mathieu-Daudé         .readonly = fr->readonly,
2438d7f2e76SPhilippe Mathieu-Daudé         .nonvolatile = fr->nonvolatile,
244533f5d66SDavid Hildenbrand         .unmergeable = fr->unmergeable,
2458d7f2e76SPhilippe Mathieu-Daudé     };
2468d7f2e76SPhilippe Mathieu-Daudé }
2478d7f2e76SPhilippe Mathieu-Daudé 
flatrange_equal(FlatRange * a,FlatRange * b)2488d7f2e76SPhilippe Mathieu-Daudé static bool flatrange_equal(FlatRange *a, FlatRange *b)
2498d7f2e76SPhilippe Mathieu-Daudé {
2508d7f2e76SPhilippe Mathieu-Daudé     return a->mr == b->mr
2518d7f2e76SPhilippe Mathieu-Daudé         && addrrange_equal(a->addr, b->addr)
2528d7f2e76SPhilippe Mathieu-Daudé         && a->offset_in_region == b->offset_in_region
2538d7f2e76SPhilippe Mathieu-Daudé         && a->romd_mode == b->romd_mode
2548d7f2e76SPhilippe Mathieu-Daudé         && a->readonly == b->readonly
255533f5d66SDavid Hildenbrand         && a->nonvolatile == b->nonvolatile
256533f5d66SDavid Hildenbrand         && a->unmergeable == b->unmergeable;
2578d7f2e76SPhilippe Mathieu-Daudé }
2588d7f2e76SPhilippe Mathieu-Daudé 
flatview_new(MemoryRegion * mr_root)2598d7f2e76SPhilippe Mathieu-Daudé static FlatView *flatview_new(MemoryRegion *mr_root)
2608d7f2e76SPhilippe Mathieu-Daudé {
2618d7f2e76SPhilippe Mathieu-Daudé     FlatView *view;
2628d7f2e76SPhilippe Mathieu-Daudé 
2638d7f2e76SPhilippe Mathieu-Daudé     view = g_new0(FlatView, 1);
2648d7f2e76SPhilippe Mathieu-Daudé     view->ref = 1;
2658d7f2e76SPhilippe Mathieu-Daudé     view->root = mr_root;
2668d7f2e76SPhilippe Mathieu-Daudé     memory_region_ref(mr_root);
2678d7f2e76SPhilippe Mathieu-Daudé     trace_flatview_new(view, mr_root);
2688d7f2e76SPhilippe Mathieu-Daudé 
2698d7f2e76SPhilippe Mathieu-Daudé     return view;
2708d7f2e76SPhilippe Mathieu-Daudé }
2718d7f2e76SPhilippe Mathieu-Daudé 
2728d7f2e76SPhilippe Mathieu-Daudé /* Insert a range into a given position.  Caller is responsible for maintaining
2738d7f2e76SPhilippe Mathieu-Daudé  * sorting order.
2748d7f2e76SPhilippe Mathieu-Daudé  */
flatview_insert(FlatView * view,unsigned pos,FlatRange * range)2758d7f2e76SPhilippe Mathieu-Daudé static void flatview_insert(FlatView *view, unsigned pos, FlatRange *range)
2768d7f2e76SPhilippe Mathieu-Daudé {
2778d7f2e76SPhilippe Mathieu-Daudé     if (view->nr == view->nr_allocated) {
2788d7f2e76SPhilippe Mathieu-Daudé         view->nr_allocated = MAX(2 * view->nr, 10);
2798d7f2e76SPhilippe Mathieu-Daudé         view->ranges = g_realloc(view->ranges,
2808d7f2e76SPhilippe Mathieu-Daudé                                     view->nr_allocated * sizeof(*view->ranges));
2818d7f2e76SPhilippe Mathieu-Daudé     }
2828d7f2e76SPhilippe Mathieu-Daudé     memmove(view->ranges + pos + 1, view->ranges + pos,
2838d7f2e76SPhilippe Mathieu-Daudé             (view->nr - pos) * sizeof(FlatRange));
2848d7f2e76SPhilippe Mathieu-Daudé     view->ranges[pos] = *range;
2858d7f2e76SPhilippe Mathieu-Daudé     memory_region_ref(range->mr);
2868d7f2e76SPhilippe Mathieu-Daudé     ++view->nr;
2878d7f2e76SPhilippe Mathieu-Daudé }
2888d7f2e76SPhilippe Mathieu-Daudé 
flatview_destroy(FlatView * view)2898d7f2e76SPhilippe Mathieu-Daudé static void flatview_destroy(FlatView *view)
2908d7f2e76SPhilippe Mathieu-Daudé {
2918d7f2e76SPhilippe Mathieu-Daudé     int i;
2928d7f2e76SPhilippe Mathieu-Daudé 
2938d7f2e76SPhilippe Mathieu-Daudé     trace_flatview_destroy(view, view->root);
2948d7f2e76SPhilippe Mathieu-Daudé     if (view->dispatch) {
2958d7f2e76SPhilippe Mathieu-Daudé         address_space_dispatch_free(view->dispatch);
2968d7f2e76SPhilippe Mathieu-Daudé     }
2978d7f2e76SPhilippe Mathieu-Daudé     for (i = 0; i < view->nr; i++) {
2988d7f2e76SPhilippe Mathieu-Daudé         memory_region_unref(view->ranges[i].mr);
2998d7f2e76SPhilippe Mathieu-Daudé     }
3008d7f2e76SPhilippe Mathieu-Daudé     g_free(view->ranges);
3018d7f2e76SPhilippe Mathieu-Daudé     memory_region_unref(view->root);
3028d7f2e76SPhilippe Mathieu-Daudé     g_free(view);
3038d7f2e76SPhilippe Mathieu-Daudé }
3048d7f2e76SPhilippe Mathieu-Daudé 
flatview_ref(FlatView * view)3058d7f2e76SPhilippe Mathieu-Daudé static bool flatview_ref(FlatView *view)
3068d7f2e76SPhilippe Mathieu-Daudé {
3078d7f2e76SPhilippe Mathieu-Daudé     return qatomic_fetch_inc_nonzero(&view->ref) > 0;
3088d7f2e76SPhilippe Mathieu-Daudé }
3098d7f2e76SPhilippe Mathieu-Daudé 
flatview_unref(FlatView * view)3108d7f2e76SPhilippe Mathieu-Daudé void flatview_unref(FlatView *view)
3118d7f2e76SPhilippe Mathieu-Daudé {
3128d7f2e76SPhilippe Mathieu-Daudé     if (qatomic_fetch_dec(&view->ref) == 1) {
3138d7f2e76SPhilippe Mathieu-Daudé         trace_flatview_destroy_rcu(view, view->root);
3148d7f2e76SPhilippe Mathieu-Daudé         assert(view->root);
3158d7f2e76SPhilippe Mathieu-Daudé         call_rcu(view, flatview_destroy, rcu);
3168d7f2e76SPhilippe Mathieu-Daudé     }
3178d7f2e76SPhilippe Mathieu-Daudé }
3188d7f2e76SPhilippe Mathieu-Daudé 
can_merge(FlatRange * r1,FlatRange * r2)3198d7f2e76SPhilippe Mathieu-Daudé static bool can_merge(FlatRange *r1, FlatRange *r2)
3208d7f2e76SPhilippe Mathieu-Daudé {
3218d7f2e76SPhilippe Mathieu-Daudé     return int128_eq(addrrange_end(r1->addr), r2->addr.start)
3228d7f2e76SPhilippe Mathieu-Daudé         && r1->mr == r2->mr
3238d7f2e76SPhilippe Mathieu-Daudé         && int128_eq(int128_add(int128_make64(r1->offset_in_region),
3248d7f2e76SPhilippe Mathieu-Daudé                                 r1->addr.size),
3258d7f2e76SPhilippe Mathieu-Daudé                      int128_make64(r2->offset_in_region))
3268d7f2e76SPhilippe Mathieu-Daudé         && r1->dirty_log_mask == r2->dirty_log_mask
3278d7f2e76SPhilippe Mathieu-Daudé         && r1->romd_mode == r2->romd_mode
3288d7f2e76SPhilippe Mathieu-Daudé         && r1->readonly == r2->readonly
329533f5d66SDavid Hildenbrand         && r1->nonvolatile == r2->nonvolatile
330533f5d66SDavid Hildenbrand         && !r1->unmergeable && !r2->unmergeable;
3318d7f2e76SPhilippe Mathieu-Daudé }
3328d7f2e76SPhilippe Mathieu-Daudé 
3338d7f2e76SPhilippe Mathieu-Daudé /* Attempt to simplify a view by merging adjacent ranges */
flatview_simplify(FlatView * view)3348d7f2e76SPhilippe Mathieu-Daudé static void flatview_simplify(FlatView *view)
3358d7f2e76SPhilippe Mathieu-Daudé {
3368d7f2e76SPhilippe Mathieu-Daudé     unsigned i, j, k;
3378d7f2e76SPhilippe Mathieu-Daudé 
3388d7f2e76SPhilippe Mathieu-Daudé     i = 0;
3398d7f2e76SPhilippe Mathieu-Daudé     while (i < view->nr) {
3408d7f2e76SPhilippe Mathieu-Daudé         j = i + 1;
3418d7f2e76SPhilippe Mathieu-Daudé         while (j < view->nr
3428d7f2e76SPhilippe Mathieu-Daudé                && can_merge(&view->ranges[j-1], &view->ranges[j])) {
3438d7f2e76SPhilippe Mathieu-Daudé             int128_addto(&view->ranges[i].addr.size, view->ranges[j].addr.size);
3448d7f2e76SPhilippe Mathieu-Daudé             ++j;
3458d7f2e76SPhilippe Mathieu-Daudé         }
3468d7f2e76SPhilippe Mathieu-Daudé         ++i;
3478d7f2e76SPhilippe Mathieu-Daudé         for (k = i; k < j; k++) {
3488d7f2e76SPhilippe Mathieu-Daudé             memory_region_unref(view->ranges[k].mr);
3498d7f2e76SPhilippe Mathieu-Daudé         }
3508d7f2e76SPhilippe Mathieu-Daudé         memmove(&view->ranges[i], &view->ranges[j],
3518d7f2e76SPhilippe Mathieu-Daudé                 (view->nr - j) * sizeof(view->ranges[j]));
3528d7f2e76SPhilippe Mathieu-Daudé         view->nr -= j - i;
3538d7f2e76SPhilippe Mathieu-Daudé     }
3548d7f2e76SPhilippe Mathieu-Daudé }
3558d7f2e76SPhilippe Mathieu-Daudé 
memory_region_big_endian(MemoryRegion * mr)3568d7f2e76SPhilippe Mathieu-Daudé static bool memory_region_big_endian(MemoryRegion *mr)
3578d7f2e76SPhilippe Mathieu-Daudé {
3588d7f2e76SPhilippe Mathieu-Daudé #if TARGET_BIG_ENDIAN
3598d7f2e76SPhilippe Mathieu-Daudé     return mr->ops->endianness != DEVICE_LITTLE_ENDIAN;
3608d7f2e76SPhilippe Mathieu-Daudé #else
3618d7f2e76SPhilippe Mathieu-Daudé     return mr->ops->endianness == DEVICE_BIG_ENDIAN;
3628d7f2e76SPhilippe Mathieu-Daudé #endif
3638d7f2e76SPhilippe Mathieu-Daudé }
3648d7f2e76SPhilippe Mathieu-Daudé 
adjust_endianness(MemoryRegion * mr,uint64_t * data,MemOp op)3658d7f2e76SPhilippe Mathieu-Daudé static void adjust_endianness(MemoryRegion *mr, uint64_t *data, MemOp op)
3668d7f2e76SPhilippe Mathieu-Daudé {
3678d7f2e76SPhilippe Mathieu-Daudé     if ((op & MO_BSWAP) != devend_memop(mr->ops->endianness)) {
3688d7f2e76SPhilippe Mathieu-Daudé         switch (op & MO_SIZE) {
3698d7f2e76SPhilippe Mathieu-Daudé         case MO_8:
3708d7f2e76SPhilippe Mathieu-Daudé             break;
3718d7f2e76SPhilippe Mathieu-Daudé         case MO_16:
3728d7f2e76SPhilippe Mathieu-Daudé             *data = bswap16(*data);
3738d7f2e76SPhilippe Mathieu-Daudé             break;
3748d7f2e76SPhilippe Mathieu-Daudé         case MO_32:
3758d7f2e76SPhilippe Mathieu-Daudé             *data = bswap32(*data);
3768d7f2e76SPhilippe Mathieu-Daudé             break;
3778d7f2e76SPhilippe Mathieu-Daudé         case MO_64:
3788d7f2e76SPhilippe Mathieu-Daudé             *data = bswap64(*data);
3798d7f2e76SPhilippe Mathieu-Daudé             break;
3808d7f2e76SPhilippe Mathieu-Daudé         default:
3818d7f2e76SPhilippe Mathieu-Daudé             g_assert_not_reached();
3828d7f2e76SPhilippe Mathieu-Daudé         }
3838d7f2e76SPhilippe Mathieu-Daudé     }
3848d7f2e76SPhilippe Mathieu-Daudé }
3858d7f2e76SPhilippe Mathieu-Daudé 
memory_region_shift_read_access(uint64_t * value,signed shift,uint64_t mask,uint64_t tmp)3868d7f2e76SPhilippe Mathieu-Daudé static inline void memory_region_shift_read_access(uint64_t *value,
3878d7f2e76SPhilippe Mathieu-Daudé                                                    signed shift,
3888d7f2e76SPhilippe Mathieu-Daudé                                                    uint64_t mask,
3898d7f2e76SPhilippe Mathieu-Daudé                                                    uint64_t tmp)
3908d7f2e76SPhilippe Mathieu-Daudé {
3918d7f2e76SPhilippe Mathieu-Daudé     if (shift >= 0) {
3928d7f2e76SPhilippe Mathieu-Daudé         *value |= (tmp & mask) << shift;
3938d7f2e76SPhilippe Mathieu-Daudé     } else {
3948d7f2e76SPhilippe Mathieu-Daudé         *value |= (tmp & mask) >> -shift;
3958d7f2e76SPhilippe Mathieu-Daudé     }
3968d7f2e76SPhilippe Mathieu-Daudé }
3978d7f2e76SPhilippe Mathieu-Daudé 
memory_region_shift_write_access(uint64_t * value,signed shift,uint64_t mask)3988d7f2e76SPhilippe Mathieu-Daudé static inline uint64_t memory_region_shift_write_access(uint64_t *value,
3998d7f2e76SPhilippe Mathieu-Daudé                                                         signed shift,
4008d7f2e76SPhilippe Mathieu-Daudé                                                         uint64_t mask)
4018d7f2e76SPhilippe Mathieu-Daudé {
4028d7f2e76SPhilippe Mathieu-Daudé     uint64_t tmp;
4038d7f2e76SPhilippe Mathieu-Daudé 
4048d7f2e76SPhilippe Mathieu-Daudé     if (shift >= 0) {
4058d7f2e76SPhilippe Mathieu-Daudé         tmp = (*value >> shift) & mask;
4068d7f2e76SPhilippe Mathieu-Daudé     } else {
4078d7f2e76SPhilippe Mathieu-Daudé         tmp = (*value << -shift) & mask;
4088d7f2e76SPhilippe Mathieu-Daudé     }
4098d7f2e76SPhilippe Mathieu-Daudé 
4108d7f2e76SPhilippe Mathieu-Daudé     return tmp;
4118d7f2e76SPhilippe Mathieu-Daudé }
4128d7f2e76SPhilippe Mathieu-Daudé 
memory_region_to_absolute_addr(MemoryRegion * mr,hwaddr offset)4138d7f2e76SPhilippe Mathieu-Daudé static hwaddr memory_region_to_absolute_addr(MemoryRegion *mr, hwaddr offset)
4148d7f2e76SPhilippe Mathieu-Daudé {
4158d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *root;
4168d7f2e76SPhilippe Mathieu-Daudé     hwaddr abs_addr = offset;
4178d7f2e76SPhilippe Mathieu-Daudé 
4188d7f2e76SPhilippe Mathieu-Daudé     abs_addr += mr->addr;
4198d7f2e76SPhilippe Mathieu-Daudé     for (root = mr; root->container; ) {
4208d7f2e76SPhilippe Mathieu-Daudé         root = root->container;
4218d7f2e76SPhilippe Mathieu-Daudé         abs_addr += root->addr;
4228d7f2e76SPhilippe Mathieu-Daudé     }
4238d7f2e76SPhilippe Mathieu-Daudé 
4248d7f2e76SPhilippe Mathieu-Daudé     return abs_addr;
4258d7f2e76SPhilippe Mathieu-Daudé }
4268d7f2e76SPhilippe Mathieu-Daudé 
get_cpu_index(void)4278d7f2e76SPhilippe Mathieu-Daudé static int get_cpu_index(void)
4288d7f2e76SPhilippe Mathieu-Daudé {
4298d7f2e76SPhilippe Mathieu-Daudé     if (current_cpu) {
4308d7f2e76SPhilippe Mathieu-Daudé         return current_cpu->cpu_index;
4318d7f2e76SPhilippe Mathieu-Daudé     }
4328d7f2e76SPhilippe Mathieu-Daudé     return -1;
4338d7f2e76SPhilippe Mathieu-Daudé }
4348d7f2e76SPhilippe Mathieu-Daudé 
memory_region_read_accessor(MemoryRegion * mr,hwaddr addr,uint64_t * value,unsigned size,signed shift,uint64_t mask,MemTxAttrs attrs)4358d7f2e76SPhilippe Mathieu-Daudé static MemTxResult  memory_region_read_accessor(MemoryRegion *mr,
4368d7f2e76SPhilippe Mathieu-Daudé                                                 hwaddr addr,
4378d7f2e76SPhilippe Mathieu-Daudé                                                 uint64_t *value,
4388d7f2e76SPhilippe Mathieu-Daudé                                                 unsigned size,
4398d7f2e76SPhilippe Mathieu-Daudé                                                 signed shift,
4408d7f2e76SPhilippe Mathieu-Daudé                                                 uint64_t mask,
4418d7f2e76SPhilippe Mathieu-Daudé                                                 MemTxAttrs attrs)
4428d7f2e76SPhilippe Mathieu-Daudé {
4438d7f2e76SPhilippe Mathieu-Daudé     uint64_t tmp;
4448d7f2e76SPhilippe Mathieu-Daudé 
4458d7f2e76SPhilippe Mathieu-Daudé     tmp = mr->ops->read(mr->opaque, addr, size);
4468d7f2e76SPhilippe Mathieu-Daudé     if (mr->subpage) {
4478d7f2e76SPhilippe Mathieu-Daudé         trace_memory_region_subpage_read(get_cpu_index(), mr, addr, tmp, size);
4488d7f2e76SPhilippe Mathieu-Daudé     } else if (trace_event_get_state_backends(TRACE_MEMORY_REGION_OPS_READ)) {
4498d7f2e76SPhilippe Mathieu-Daudé         hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
4508d7f2e76SPhilippe Mathieu-Daudé         trace_memory_region_ops_read(get_cpu_index(), mr, abs_addr, tmp, size,
4518d7f2e76SPhilippe Mathieu-Daudé                                      memory_region_name(mr));
4528d7f2e76SPhilippe Mathieu-Daudé     }
4538d7f2e76SPhilippe Mathieu-Daudé     memory_region_shift_read_access(value, shift, mask, tmp);
4548d7f2e76SPhilippe Mathieu-Daudé     return MEMTX_OK;
4558d7f2e76SPhilippe Mathieu-Daudé }
4568d7f2e76SPhilippe Mathieu-Daudé 
memory_region_read_with_attrs_accessor(MemoryRegion * mr,hwaddr addr,uint64_t * value,unsigned size,signed shift,uint64_t mask,MemTxAttrs attrs)4578d7f2e76SPhilippe Mathieu-Daudé static MemTxResult memory_region_read_with_attrs_accessor(MemoryRegion *mr,
4588d7f2e76SPhilippe Mathieu-Daudé                                                           hwaddr addr,
4598d7f2e76SPhilippe Mathieu-Daudé                                                           uint64_t *value,
4608d7f2e76SPhilippe Mathieu-Daudé                                                           unsigned size,
4618d7f2e76SPhilippe Mathieu-Daudé                                                           signed shift,
4628d7f2e76SPhilippe Mathieu-Daudé                                                           uint64_t mask,
4638d7f2e76SPhilippe Mathieu-Daudé                                                           MemTxAttrs attrs)
4648d7f2e76SPhilippe Mathieu-Daudé {
4658d7f2e76SPhilippe Mathieu-Daudé     uint64_t tmp = 0;
4668d7f2e76SPhilippe Mathieu-Daudé     MemTxResult r;
4678d7f2e76SPhilippe Mathieu-Daudé 
4688d7f2e76SPhilippe Mathieu-Daudé     r = mr->ops->read_with_attrs(mr->opaque, addr, &tmp, size, attrs);
4698d7f2e76SPhilippe Mathieu-Daudé     if (mr->subpage) {
4708d7f2e76SPhilippe Mathieu-Daudé         trace_memory_region_subpage_read(get_cpu_index(), mr, addr, tmp, size);
4718d7f2e76SPhilippe Mathieu-Daudé     } else if (trace_event_get_state_backends(TRACE_MEMORY_REGION_OPS_READ)) {
4728d7f2e76SPhilippe Mathieu-Daudé         hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
4738d7f2e76SPhilippe Mathieu-Daudé         trace_memory_region_ops_read(get_cpu_index(), mr, abs_addr, tmp, size,
4748d7f2e76SPhilippe Mathieu-Daudé                                      memory_region_name(mr));
4758d7f2e76SPhilippe Mathieu-Daudé     }
4768d7f2e76SPhilippe Mathieu-Daudé     memory_region_shift_read_access(value, shift, mask, tmp);
4778d7f2e76SPhilippe Mathieu-Daudé     return r;
4788d7f2e76SPhilippe Mathieu-Daudé }
4798d7f2e76SPhilippe Mathieu-Daudé 
memory_region_write_accessor(MemoryRegion * mr,hwaddr addr,uint64_t * value,unsigned size,signed shift,uint64_t mask,MemTxAttrs attrs)4808d7f2e76SPhilippe Mathieu-Daudé static MemTxResult memory_region_write_accessor(MemoryRegion *mr,
4818d7f2e76SPhilippe Mathieu-Daudé                                                 hwaddr addr,
4828d7f2e76SPhilippe Mathieu-Daudé                                                 uint64_t *value,
4838d7f2e76SPhilippe Mathieu-Daudé                                                 unsigned size,
4848d7f2e76SPhilippe Mathieu-Daudé                                                 signed shift,
4858d7f2e76SPhilippe Mathieu-Daudé                                                 uint64_t mask,
4868d7f2e76SPhilippe Mathieu-Daudé                                                 MemTxAttrs attrs)
4878d7f2e76SPhilippe Mathieu-Daudé {
4888d7f2e76SPhilippe Mathieu-Daudé     uint64_t tmp = memory_region_shift_write_access(value, shift, mask);
4898d7f2e76SPhilippe Mathieu-Daudé 
4908d7f2e76SPhilippe Mathieu-Daudé     if (mr->subpage) {
4918d7f2e76SPhilippe Mathieu-Daudé         trace_memory_region_subpage_write(get_cpu_index(), mr, addr, tmp, size);
4928d7f2e76SPhilippe Mathieu-Daudé     } else if (trace_event_get_state_backends(TRACE_MEMORY_REGION_OPS_WRITE)) {
4938d7f2e76SPhilippe Mathieu-Daudé         hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
4948d7f2e76SPhilippe Mathieu-Daudé         trace_memory_region_ops_write(get_cpu_index(), mr, abs_addr, tmp, size,
4958d7f2e76SPhilippe Mathieu-Daudé                                       memory_region_name(mr));
4968d7f2e76SPhilippe Mathieu-Daudé     }
4978d7f2e76SPhilippe Mathieu-Daudé     mr->ops->write(mr->opaque, addr, tmp, size);
4988d7f2e76SPhilippe Mathieu-Daudé     return MEMTX_OK;
4998d7f2e76SPhilippe Mathieu-Daudé }
5008d7f2e76SPhilippe Mathieu-Daudé 
memory_region_write_with_attrs_accessor(MemoryRegion * mr,hwaddr addr,uint64_t * value,unsigned size,signed shift,uint64_t mask,MemTxAttrs attrs)5018d7f2e76SPhilippe Mathieu-Daudé static MemTxResult memory_region_write_with_attrs_accessor(MemoryRegion *mr,
5028d7f2e76SPhilippe Mathieu-Daudé                                                            hwaddr addr,
5038d7f2e76SPhilippe Mathieu-Daudé                                                            uint64_t *value,
5048d7f2e76SPhilippe Mathieu-Daudé                                                            unsigned size,
5058d7f2e76SPhilippe Mathieu-Daudé                                                            signed shift,
5068d7f2e76SPhilippe Mathieu-Daudé                                                            uint64_t mask,
5078d7f2e76SPhilippe Mathieu-Daudé                                                            MemTxAttrs attrs)
5088d7f2e76SPhilippe Mathieu-Daudé {
5098d7f2e76SPhilippe Mathieu-Daudé     uint64_t tmp = memory_region_shift_write_access(value, shift, mask);
5108d7f2e76SPhilippe Mathieu-Daudé 
5118d7f2e76SPhilippe Mathieu-Daudé     if (mr->subpage) {
5128d7f2e76SPhilippe Mathieu-Daudé         trace_memory_region_subpage_write(get_cpu_index(), mr, addr, tmp, size);
5138d7f2e76SPhilippe Mathieu-Daudé     } else if (trace_event_get_state_backends(TRACE_MEMORY_REGION_OPS_WRITE)) {
5148d7f2e76SPhilippe Mathieu-Daudé         hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
5158d7f2e76SPhilippe Mathieu-Daudé         trace_memory_region_ops_write(get_cpu_index(), mr, abs_addr, tmp, size,
5168d7f2e76SPhilippe Mathieu-Daudé                                       memory_region_name(mr));
5178d7f2e76SPhilippe Mathieu-Daudé     }
5188d7f2e76SPhilippe Mathieu-Daudé     return mr->ops->write_with_attrs(mr->opaque, addr, tmp, size, attrs);
5198d7f2e76SPhilippe Mathieu-Daudé }
5208d7f2e76SPhilippe Mathieu-Daudé 
access_with_adjusted_size_aligned(hwaddr addr,uint64_t * value,unsigned size,unsigned access_size_min,unsigned access_size_max,MemTxResult (* access_fn)(MemoryRegion * mr,hwaddr addr,uint64_t * value,unsigned size,signed shift,uint64_t mask,MemTxAttrs attrs),MemoryRegion * mr,MemTxAttrs attrs)521*557e1d67SAndrew Jeffery static MemTxResult access_with_adjusted_size_aligned(hwaddr addr,
5228d7f2e76SPhilippe Mathieu-Daudé                                       uint64_t *value,
5238d7f2e76SPhilippe Mathieu-Daudé                                       unsigned size,
5248d7f2e76SPhilippe Mathieu-Daudé                                       unsigned access_size_min,
5258d7f2e76SPhilippe Mathieu-Daudé                                       unsigned access_size_max,
5268d7f2e76SPhilippe Mathieu-Daudé                                       MemTxResult (*access_fn)
5278d7f2e76SPhilippe Mathieu-Daudé                                                   (MemoryRegion *mr,
5288d7f2e76SPhilippe Mathieu-Daudé                                                    hwaddr addr,
5298d7f2e76SPhilippe Mathieu-Daudé                                                    uint64_t *value,
5308d7f2e76SPhilippe Mathieu-Daudé                                                    unsigned size,
5318d7f2e76SPhilippe Mathieu-Daudé                                                    signed shift,
5328d7f2e76SPhilippe Mathieu-Daudé                                                    uint64_t mask,
5338d7f2e76SPhilippe Mathieu-Daudé                                                    MemTxAttrs attrs),
5348d7f2e76SPhilippe Mathieu-Daudé                                       MemoryRegion *mr,
5358d7f2e76SPhilippe Mathieu-Daudé                                       MemTxAttrs attrs)
5368d7f2e76SPhilippe Mathieu-Daudé {
5378d7f2e76SPhilippe Mathieu-Daudé     uint64_t access_mask;
5388d7f2e76SPhilippe Mathieu-Daudé     unsigned access_size;
5398d7f2e76SPhilippe Mathieu-Daudé     unsigned i;
5408d7f2e76SPhilippe Mathieu-Daudé     MemTxResult r = MEMTX_OK;
5418d7f2e76SPhilippe Mathieu-Daudé     bool reentrancy_guard_applied = false;
5428d7f2e76SPhilippe Mathieu-Daudé 
5438d7f2e76SPhilippe Mathieu-Daudé     if (!access_size_min) {
5448d7f2e76SPhilippe Mathieu-Daudé         access_size_min = 1;
5458d7f2e76SPhilippe Mathieu-Daudé     }
5468d7f2e76SPhilippe Mathieu-Daudé     if (!access_size_max) {
5478d7f2e76SPhilippe Mathieu-Daudé         access_size_max = 4;
5488d7f2e76SPhilippe Mathieu-Daudé     }
5498d7f2e76SPhilippe Mathieu-Daudé 
5508d7f2e76SPhilippe Mathieu-Daudé     /* Do not allow more than one simultaneous access to a device's IO Regions */
5518d7f2e76SPhilippe Mathieu-Daudé     if (mr->dev && !mr->disable_reentrancy_guard &&
5528d7f2e76SPhilippe Mathieu-Daudé         !mr->ram_device && !mr->ram && !mr->rom_device && !mr->readonly) {
5538d7f2e76SPhilippe Mathieu-Daudé         if (mr->dev->mem_reentrancy_guard.engaged_in_io) {
5548d7f2e76SPhilippe Mathieu-Daudé             warn_report_once("Blocked re-entrant IO on MemoryRegion: "
5558d7f2e76SPhilippe Mathieu-Daudé                              "%s at addr: 0x%" HWADDR_PRIX,
5568d7f2e76SPhilippe Mathieu-Daudé                              memory_region_name(mr), addr);
5578d7f2e76SPhilippe Mathieu-Daudé             return MEMTX_ACCESS_ERROR;
5588d7f2e76SPhilippe Mathieu-Daudé         }
5598d7f2e76SPhilippe Mathieu-Daudé         mr->dev->mem_reentrancy_guard.engaged_in_io = true;
5608d7f2e76SPhilippe Mathieu-Daudé         reentrancy_guard_applied = true;
5618d7f2e76SPhilippe Mathieu-Daudé     }
5628d7f2e76SPhilippe Mathieu-Daudé 
5638d7f2e76SPhilippe Mathieu-Daudé     access_size = MAX(MIN(size, access_size_max), access_size_min);
5648d7f2e76SPhilippe Mathieu-Daudé     access_mask = MAKE_64BIT_MASK(0, access_size * 8);
5658d7f2e76SPhilippe Mathieu-Daudé     if (memory_region_big_endian(mr)) {
5668d7f2e76SPhilippe Mathieu-Daudé         for (i = 0; i < size; i += access_size) {
5678d7f2e76SPhilippe Mathieu-Daudé             r |= access_fn(mr, addr + i, value, access_size,
5688d7f2e76SPhilippe Mathieu-Daudé                         (size - access_size - i) * 8, access_mask, attrs);
5698d7f2e76SPhilippe Mathieu-Daudé         }
5708d7f2e76SPhilippe Mathieu-Daudé     } else {
5718d7f2e76SPhilippe Mathieu-Daudé         for (i = 0; i < size; i += access_size) {
5728d7f2e76SPhilippe Mathieu-Daudé             r |= access_fn(mr, addr + i, value, access_size, i * 8,
5738d7f2e76SPhilippe Mathieu-Daudé                         access_mask, attrs);
5748d7f2e76SPhilippe Mathieu-Daudé         }
5758d7f2e76SPhilippe Mathieu-Daudé     }
5768d7f2e76SPhilippe Mathieu-Daudé     if (mr->dev && reentrancy_guard_applied) {
5778d7f2e76SPhilippe Mathieu-Daudé         mr->dev->mem_reentrancy_guard.engaged_in_io = false;
5788d7f2e76SPhilippe Mathieu-Daudé     }
5798d7f2e76SPhilippe Mathieu-Daudé     return r;
5808d7f2e76SPhilippe Mathieu-Daudé }
5818d7f2e76SPhilippe Mathieu-Daudé 
582*557e1d67SAndrew Jeffery /* Assume power-of-two size */
583*557e1d67SAndrew Jeffery #define align_down(addr, size) ((addr) & ~((size) - 1))
584*557e1d67SAndrew Jeffery #define align_up(addr, size) \
585*557e1d67SAndrew Jeffery     ({ typeof(size) __size = size;  \
586*557e1d67SAndrew Jeffery         align_down((addr) + (__size) - 1, (__size)); })
587*557e1d67SAndrew Jeffery 
access_with_adjusted_size_unaligned(hwaddr addr,uint64_t * value,unsigned size,unsigned access_size_min,unsigned access_size_max,bool unaligned,MemTxResult (* access)(MemoryRegion * mr,hwaddr addr,uint64_t * value,unsigned size,signed shift,uint64_t mask,MemTxAttrs attrs),MemoryRegion * mr,MemTxAttrs attrs)588*557e1d67SAndrew Jeffery static MemTxResult access_with_adjusted_size_unaligned(hwaddr addr,
589*557e1d67SAndrew Jeffery                                       uint64_t *value,
590*557e1d67SAndrew Jeffery                                       unsigned size,
591*557e1d67SAndrew Jeffery                                       unsigned access_size_min,
592*557e1d67SAndrew Jeffery                                       unsigned access_size_max,
593*557e1d67SAndrew Jeffery                                       bool unaligned,
594*557e1d67SAndrew Jeffery                                       MemTxResult (*access)(MemoryRegion *mr,
595*557e1d67SAndrew Jeffery                                                             hwaddr addr,
596*557e1d67SAndrew Jeffery                                                             uint64_t *value,
597*557e1d67SAndrew Jeffery                                                             unsigned size,
598*557e1d67SAndrew Jeffery                                                             signed shift,
599*557e1d67SAndrew Jeffery                                                             uint64_t mask,
600*557e1d67SAndrew Jeffery                                                             MemTxAttrs attrs),
601*557e1d67SAndrew Jeffery                                       MemoryRegion *mr,
602*557e1d67SAndrew Jeffery                                       MemTxAttrs attrs)
603*557e1d67SAndrew Jeffery {
604*557e1d67SAndrew Jeffery     uint64_t access_value = 0;
605*557e1d67SAndrew Jeffery     MemTxResult r = MEMTX_OK;
606*557e1d67SAndrew Jeffery     hwaddr access_addr[2];
607*557e1d67SAndrew Jeffery     uint64_t access_mask;
608*557e1d67SAndrew Jeffery     unsigned access_size;
609*557e1d67SAndrew Jeffery 
610*557e1d67SAndrew Jeffery     if (unlikely(!access_size_min)) {
611*557e1d67SAndrew Jeffery         access_size_min = 1;
612*557e1d67SAndrew Jeffery     }
613*557e1d67SAndrew Jeffery     if (unlikely(!access_size_max)) {
614*557e1d67SAndrew Jeffery         access_size_max = 4;
615*557e1d67SAndrew Jeffery     }
616*557e1d67SAndrew Jeffery 
617*557e1d67SAndrew Jeffery     access_size = MAX(MIN(size, access_size_max), access_size_min);
618*557e1d67SAndrew Jeffery     access_addr[0] = align_down(addr, access_size);
619*557e1d67SAndrew Jeffery     access_addr[1] = align_up(addr + size, access_size);
620*557e1d67SAndrew Jeffery 
621*557e1d67SAndrew Jeffery     if (memory_region_big_endian(mr)) {
622*557e1d67SAndrew Jeffery         hwaddr cur;
623*557e1d67SAndrew Jeffery 
624*557e1d67SAndrew Jeffery         /* XXX: Big-endian path is untested...  */
625*557e1d67SAndrew Jeffery 
626*557e1d67SAndrew Jeffery         for (cur = access_addr[0]; cur < access_addr[1]; cur += access_size) {
627*557e1d67SAndrew Jeffery             uint64_t mask_bounds[2];
628*557e1d67SAndrew Jeffery 
629*557e1d67SAndrew Jeffery             mask_bounds[0] = MAX(addr, cur) - cur;
630*557e1d67SAndrew Jeffery             mask_bounds[1] =
631*557e1d67SAndrew Jeffery                 MIN(addr + size, align_up(cur + 1, access_size)) - cur;
632*557e1d67SAndrew Jeffery 
633*557e1d67SAndrew Jeffery             access_mask = (-1ULL << mask_bounds[0] * 8) &
634*557e1d67SAndrew Jeffery                 (-1ULL >> (64 - mask_bounds[1] * 8));
635*557e1d67SAndrew Jeffery 
636*557e1d67SAndrew Jeffery             r |= access(mr, cur, &access_value, access_size,
637*557e1d67SAndrew Jeffery                   (size - access_size - (MAX(addr, cur) - addr)),
638*557e1d67SAndrew Jeffery                   access_mask, attrs);
639*557e1d67SAndrew Jeffery 
640*557e1d67SAndrew Jeffery             /* XXX: Can't do this hack for writes */
641*557e1d67SAndrew Jeffery             access_value >>= mask_bounds[0] * 8;
642*557e1d67SAndrew Jeffery         }
643*557e1d67SAndrew Jeffery     } else {
644*557e1d67SAndrew Jeffery         hwaddr cur;
645*557e1d67SAndrew Jeffery 
646*557e1d67SAndrew Jeffery         for (cur = access_addr[0]; cur < access_addr[1]; cur += access_size) {
647*557e1d67SAndrew Jeffery             uint64_t mask_bounds[2];
648*557e1d67SAndrew Jeffery 
649*557e1d67SAndrew Jeffery             mask_bounds[0] = MAX(addr, cur) - cur;
650*557e1d67SAndrew Jeffery             mask_bounds[1] =
651*557e1d67SAndrew Jeffery                 MIN(addr + size, align_up(cur + 1, access_size)) - cur;
652*557e1d67SAndrew Jeffery 
653*557e1d67SAndrew Jeffery             access_mask = (-1ULL << mask_bounds[0] * 8) &
654*557e1d67SAndrew Jeffery                 (-1ULL >> (64 - mask_bounds[1] * 8));
655*557e1d67SAndrew Jeffery 
656*557e1d67SAndrew Jeffery             r |= access(mr, cur, &access_value, access_size,
657*557e1d67SAndrew Jeffery                   (MAX(addr, cur) - addr), access_mask, attrs);
658*557e1d67SAndrew Jeffery 
659*557e1d67SAndrew Jeffery             /* XXX: Can't do this hack for writes */
660*557e1d67SAndrew Jeffery             access_value >>= mask_bounds[0] * 8;
661*557e1d67SAndrew Jeffery         }
662*557e1d67SAndrew Jeffery     }
663*557e1d67SAndrew Jeffery 
664*557e1d67SAndrew Jeffery     *value = access_value;
665*557e1d67SAndrew Jeffery 
666*557e1d67SAndrew Jeffery     return r;
667*557e1d67SAndrew Jeffery }
668*557e1d67SAndrew Jeffery 
access_with_adjusted_size(hwaddr addr,uint64_t * value,unsigned size,unsigned access_size_min,unsigned access_size_max,bool unaligned,MemTxResult (* access)(MemoryRegion * mr,hwaddr addr,uint64_t * value,unsigned size,signed shift,uint64_t mask,MemTxAttrs attrs),MemoryRegion * mr,MemTxAttrs attrs)669*557e1d67SAndrew Jeffery static inline MemTxResult access_with_adjusted_size(hwaddr addr,
670*557e1d67SAndrew Jeffery                                       uint64_t *value,
671*557e1d67SAndrew Jeffery                                       unsigned size,
672*557e1d67SAndrew Jeffery                                       unsigned access_size_min,
673*557e1d67SAndrew Jeffery                                       unsigned access_size_max,
674*557e1d67SAndrew Jeffery                                       bool unaligned,
675*557e1d67SAndrew Jeffery                                       MemTxResult (*access)(MemoryRegion *mr,
676*557e1d67SAndrew Jeffery                                                             hwaddr addr,
677*557e1d67SAndrew Jeffery                                                             uint64_t *value,
678*557e1d67SAndrew Jeffery                                                             unsigned size,
679*557e1d67SAndrew Jeffery                                                             signed shift,
680*557e1d67SAndrew Jeffery                                                             uint64_t mask,
681*557e1d67SAndrew Jeffery                                                             MemTxAttrs attrs),
682*557e1d67SAndrew Jeffery                                       MemoryRegion *mr,
683*557e1d67SAndrew Jeffery                                       MemTxAttrs attrs)
684*557e1d67SAndrew Jeffery {
685*557e1d67SAndrew Jeffery     unsigned access_size;
686*557e1d67SAndrew Jeffery 
687*557e1d67SAndrew Jeffery     if (!access_size_min) {
688*557e1d67SAndrew Jeffery         access_size_min = 1;
689*557e1d67SAndrew Jeffery     }
690*557e1d67SAndrew Jeffery     if (!access_size_max) {
691*557e1d67SAndrew Jeffery         access_size_max = 4;
692*557e1d67SAndrew Jeffery     }
693*557e1d67SAndrew Jeffery 
694*557e1d67SAndrew Jeffery     access_size = MAX(MIN(size, access_size_max), access_size_min);
695*557e1d67SAndrew Jeffery 
696*557e1d67SAndrew Jeffery     /* Handle unaligned accesses if the model only supports natural alignment */
697*557e1d67SAndrew Jeffery     if (unlikely((addr & (access_size - 1)) && !unaligned)) {
698*557e1d67SAndrew Jeffery         return access_with_adjusted_size_unaligned(addr, value, size,
699*557e1d67SAndrew Jeffery                 access_size_min, access_size_max, unaligned, access, mr, attrs);
700*557e1d67SAndrew Jeffery     }
701*557e1d67SAndrew Jeffery 
702*557e1d67SAndrew Jeffery     /*
703*557e1d67SAndrew Jeffery      * Otherwise, if the access is aligned or the model specifies it can handle
704*557e1d67SAndrew Jeffery      * unaligned accesses, use the 'aligned' handler
705*557e1d67SAndrew Jeffery      */
706*557e1d67SAndrew Jeffery     return access_with_adjusted_size_aligned(addr, value, size,
707*557e1d67SAndrew Jeffery             access_size_min, access_size_max, access, mr, attrs);
708*557e1d67SAndrew Jeffery }
709*557e1d67SAndrew Jeffery 
memory_region_to_address_space(MemoryRegion * mr)7108d7f2e76SPhilippe Mathieu-Daudé static AddressSpace *memory_region_to_address_space(MemoryRegion *mr)
7118d7f2e76SPhilippe Mathieu-Daudé {
7128d7f2e76SPhilippe Mathieu-Daudé     AddressSpace *as;
7138d7f2e76SPhilippe Mathieu-Daudé 
7148d7f2e76SPhilippe Mathieu-Daudé     while (mr->container) {
7158d7f2e76SPhilippe Mathieu-Daudé         mr = mr->container;
7168d7f2e76SPhilippe Mathieu-Daudé     }
7178d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
7188d7f2e76SPhilippe Mathieu-Daudé         if (mr == as->root) {
7198d7f2e76SPhilippe Mathieu-Daudé             return as;
7208d7f2e76SPhilippe Mathieu-Daudé         }
7218d7f2e76SPhilippe Mathieu-Daudé     }
7228d7f2e76SPhilippe Mathieu-Daudé     return NULL;
7238d7f2e76SPhilippe Mathieu-Daudé }
7248d7f2e76SPhilippe Mathieu-Daudé 
7258d7f2e76SPhilippe Mathieu-Daudé /* Render a memory region into the global view.  Ranges in @view obscure
7268d7f2e76SPhilippe Mathieu-Daudé  * ranges in @mr.
7278d7f2e76SPhilippe Mathieu-Daudé  */
render_memory_region(FlatView * view,MemoryRegion * mr,Int128 base,AddrRange clip,bool readonly,bool nonvolatile,bool unmergeable)7288d7f2e76SPhilippe Mathieu-Daudé static void render_memory_region(FlatView *view,
7298d7f2e76SPhilippe Mathieu-Daudé                                  MemoryRegion *mr,
7308d7f2e76SPhilippe Mathieu-Daudé                                  Int128 base,
7318d7f2e76SPhilippe Mathieu-Daudé                                  AddrRange clip,
7328d7f2e76SPhilippe Mathieu-Daudé                                  bool readonly,
733533f5d66SDavid Hildenbrand                                  bool nonvolatile,
734533f5d66SDavid Hildenbrand                                  bool unmergeable)
7358d7f2e76SPhilippe Mathieu-Daudé {
7368d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *subregion;
7378d7f2e76SPhilippe Mathieu-Daudé     unsigned i;
7388d7f2e76SPhilippe Mathieu-Daudé     hwaddr offset_in_region;
7398d7f2e76SPhilippe Mathieu-Daudé     Int128 remain;
7408d7f2e76SPhilippe Mathieu-Daudé     Int128 now;
7418d7f2e76SPhilippe Mathieu-Daudé     FlatRange fr;
7428d7f2e76SPhilippe Mathieu-Daudé     AddrRange tmp;
7438d7f2e76SPhilippe Mathieu-Daudé 
7448d7f2e76SPhilippe Mathieu-Daudé     if (!mr->enabled) {
7458d7f2e76SPhilippe Mathieu-Daudé         return;
7468d7f2e76SPhilippe Mathieu-Daudé     }
7478d7f2e76SPhilippe Mathieu-Daudé 
7488d7f2e76SPhilippe Mathieu-Daudé     int128_addto(&base, int128_make64(mr->addr));
7498d7f2e76SPhilippe Mathieu-Daudé     readonly |= mr->readonly;
7508d7f2e76SPhilippe Mathieu-Daudé     nonvolatile |= mr->nonvolatile;
751533f5d66SDavid Hildenbrand     unmergeable |= mr->unmergeable;
7528d7f2e76SPhilippe Mathieu-Daudé 
7538d7f2e76SPhilippe Mathieu-Daudé     tmp = addrrange_make(base, mr->size);
7548d7f2e76SPhilippe Mathieu-Daudé 
7558d7f2e76SPhilippe Mathieu-Daudé     if (!addrrange_intersects(tmp, clip)) {
7568d7f2e76SPhilippe Mathieu-Daudé         return;
7578d7f2e76SPhilippe Mathieu-Daudé     }
7588d7f2e76SPhilippe Mathieu-Daudé 
7598d7f2e76SPhilippe Mathieu-Daudé     clip = addrrange_intersection(tmp, clip);
7608d7f2e76SPhilippe Mathieu-Daudé 
7618d7f2e76SPhilippe Mathieu-Daudé     if (mr->alias) {
7628d7f2e76SPhilippe Mathieu-Daudé         int128_subfrom(&base, int128_make64(mr->alias->addr));
7638d7f2e76SPhilippe Mathieu-Daudé         int128_subfrom(&base, int128_make64(mr->alias_offset));
7648d7f2e76SPhilippe Mathieu-Daudé         render_memory_region(view, mr->alias, base, clip,
765533f5d66SDavid Hildenbrand                              readonly, nonvolatile, unmergeable);
7668d7f2e76SPhilippe Mathieu-Daudé         return;
7678d7f2e76SPhilippe Mathieu-Daudé     }
7688d7f2e76SPhilippe Mathieu-Daudé 
7698d7f2e76SPhilippe Mathieu-Daudé     /* Render subregions in priority order. */
7708d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) {
7718d7f2e76SPhilippe Mathieu-Daudé         render_memory_region(view, subregion, base, clip,
772533f5d66SDavid Hildenbrand                              readonly, nonvolatile, unmergeable);
7738d7f2e76SPhilippe Mathieu-Daudé     }
7748d7f2e76SPhilippe Mathieu-Daudé 
7758d7f2e76SPhilippe Mathieu-Daudé     if (!mr->terminates) {
7768d7f2e76SPhilippe Mathieu-Daudé         return;
7778d7f2e76SPhilippe Mathieu-Daudé     }
7788d7f2e76SPhilippe Mathieu-Daudé 
7798d7f2e76SPhilippe Mathieu-Daudé     offset_in_region = int128_get64(int128_sub(clip.start, base));
7808d7f2e76SPhilippe Mathieu-Daudé     base = clip.start;
7818d7f2e76SPhilippe Mathieu-Daudé     remain = clip.size;
7828d7f2e76SPhilippe Mathieu-Daudé 
7838d7f2e76SPhilippe Mathieu-Daudé     fr.mr = mr;
7848d7f2e76SPhilippe Mathieu-Daudé     fr.dirty_log_mask = memory_region_get_dirty_log_mask(mr);
7858d7f2e76SPhilippe Mathieu-Daudé     fr.romd_mode = mr->romd_mode;
7868d7f2e76SPhilippe Mathieu-Daudé     fr.readonly = readonly;
7878d7f2e76SPhilippe Mathieu-Daudé     fr.nonvolatile = nonvolatile;
788533f5d66SDavid Hildenbrand     fr.unmergeable = unmergeable;
7898d7f2e76SPhilippe Mathieu-Daudé 
7908d7f2e76SPhilippe Mathieu-Daudé     /* Render the region itself into any gaps left by the current view. */
7918d7f2e76SPhilippe Mathieu-Daudé     for (i = 0; i < view->nr && int128_nz(remain); ++i) {
7928d7f2e76SPhilippe Mathieu-Daudé         if (int128_ge(base, addrrange_end(view->ranges[i].addr))) {
7938d7f2e76SPhilippe Mathieu-Daudé             continue;
7948d7f2e76SPhilippe Mathieu-Daudé         }
7958d7f2e76SPhilippe Mathieu-Daudé         if (int128_lt(base, view->ranges[i].addr.start)) {
7968d7f2e76SPhilippe Mathieu-Daudé             now = int128_min(remain,
7978d7f2e76SPhilippe Mathieu-Daudé                              int128_sub(view->ranges[i].addr.start, base));
7988d7f2e76SPhilippe Mathieu-Daudé             fr.offset_in_region = offset_in_region;
7998d7f2e76SPhilippe Mathieu-Daudé             fr.addr = addrrange_make(base, now);
8008d7f2e76SPhilippe Mathieu-Daudé             flatview_insert(view, i, &fr);
8018d7f2e76SPhilippe Mathieu-Daudé             ++i;
8028d7f2e76SPhilippe Mathieu-Daudé             int128_addto(&base, now);
8038d7f2e76SPhilippe Mathieu-Daudé             offset_in_region += int128_get64(now);
8048d7f2e76SPhilippe Mathieu-Daudé             int128_subfrom(&remain, now);
8058d7f2e76SPhilippe Mathieu-Daudé         }
8068d7f2e76SPhilippe Mathieu-Daudé         now = int128_sub(int128_min(int128_add(base, remain),
8078d7f2e76SPhilippe Mathieu-Daudé                                     addrrange_end(view->ranges[i].addr)),
8088d7f2e76SPhilippe Mathieu-Daudé                          base);
8098d7f2e76SPhilippe Mathieu-Daudé         int128_addto(&base, now);
8108d7f2e76SPhilippe Mathieu-Daudé         offset_in_region += int128_get64(now);
8118d7f2e76SPhilippe Mathieu-Daudé         int128_subfrom(&remain, now);
8128d7f2e76SPhilippe Mathieu-Daudé     }
8138d7f2e76SPhilippe Mathieu-Daudé     if (int128_nz(remain)) {
8148d7f2e76SPhilippe Mathieu-Daudé         fr.offset_in_region = offset_in_region;
8158d7f2e76SPhilippe Mathieu-Daudé         fr.addr = addrrange_make(base, remain);
8168d7f2e76SPhilippe Mathieu-Daudé         flatview_insert(view, i, &fr);
8178d7f2e76SPhilippe Mathieu-Daudé     }
8188d7f2e76SPhilippe Mathieu-Daudé }
8198d7f2e76SPhilippe Mathieu-Daudé 
flatview_for_each_range(FlatView * fv,flatview_cb cb,void * opaque)8208d7f2e76SPhilippe Mathieu-Daudé void flatview_for_each_range(FlatView *fv, flatview_cb cb , void *opaque)
8218d7f2e76SPhilippe Mathieu-Daudé {
8228d7f2e76SPhilippe Mathieu-Daudé     FlatRange *fr;
8238d7f2e76SPhilippe Mathieu-Daudé 
8248d7f2e76SPhilippe Mathieu-Daudé     assert(fv);
8258d7f2e76SPhilippe Mathieu-Daudé     assert(cb);
8268d7f2e76SPhilippe Mathieu-Daudé 
8278d7f2e76SPhilippe Mathieu-Daudé     FOR_EACH_FLAT_RANGE(fr, fv) {
8288d7f2e76SPhilippe Mathieu-Daudé         if (cb(fr->addr.start, fr->addr.size, fr->mr,
8298d7f2e76SPhilippe Mathieu-Daudé                fr->offset_in_region, opaque)) {
8308d7f2e76SPhilippe Mathieu-Daudé             break;
8318d7f2e76SPhilippe Mathieu-Daudé         }
8328d7f2e76SPhilippe Mathieu-Daudé     }
8338d7f2e76SPhilippe Mathieu-Daudé }
8348d7f2e76SPhilippe Mathieu-Daudé 
memory_region_get_flatview_root(MemoryRegion * mr)8358d7f2e76SPhilippe Mathieu-Daudé static MemoryRegion *memory_region_get_flatview_root(MemoryRegion *mr)
8368d7f2e76SPhilippe Mathieu-Daudé {
8378d7f2e76SPhilippe Mathieu-Daudé     while (mr->enabled) {
8388d7f2e76SPhilippe Mathieu-Daudé         if (mr->alias) {
8398d7f2e76SPhilippe Mathieu-Daudé             if (!mr->alias_offset && int128_ge(mr->size, mr->alias->size)) {
8408d7f2e76SPhilippe Mathieu-Daudé                 /* The alias is included in its entirety.  Use it as
8418d7f2e76SPhilippe Mathieu-Daudé                  * the "real" root, so that we can share more FlatViews.
8428d7f2e76SPhilippe Mathieu-Daudé                  */
8438d7f2e76SPhilippe Mathieu-Daudé                 mr = mr->alias;
8448d7f2e76SPhilippe Mathieu-Daudé                 continue;
8458d7f2e76SPhilippe Mathieu-Daudé             }
8468d7f2e76SPhilippe Mathieu-Daudé         } else if (!mr->terminates) {
8478d7f2e76SPhilippe Mathieu-Daudé             unsigned int found = 0;
8488d7f2e76SPhilippe Mathieu-Daudé             MemoryRegion *child, *next = NULL;
8498d7f2e76SPhilippe Mathieu-Daudé             QTAILQ_FOREACH(child, &mr->subregions, subregions_link) {
8508d7f2e76SPhilippe Mathieu-Daudé                 if (child->enabled) {
8518d7f2e76SPhilippe Mathieu-Daudé                     if (++found > 1) {
8528d7f2e76SPhilippe Mathieu-Daudé                         next = NULL;
8538d7f2e76SPhilippe Mathieu-Daudé                         break;
8548d7f2e76SPhilippe Mathieu-Daudé                     }
8558d7f2e76SPhilippe Mathieu-Daudé                     if (!child->addr && int128_ge(mr->size, child->size)) {
8568d7f2e76SPhilippe Mathieu-Daudé                         /* A child is included in its entirety.  If it's the only
8578d7f2e76SPhilippe Mathieu-Daudé                          * enabled one, use it in the hope of finding an alias down the
8588d7f2e76SPhilippe Mathieu-Daudé                          * way. This will also let us share FlatViews.
8598d7f2e76SPhilippe Mathieu-Daudé                          */
8608d7f2e76SPhilippe Mathieu-Daudé                         next = child;
8618d7f2e76SPhilippe Mathieu-Daudé                     }
8628d7f2e76SPhilippe Mathieu-Daudé                 }
8638d7f2e76SPhilippe Mathieu-Daudé             }
8648d7f2e76SPhilippe Mathieu-Daudé             if (found == 0) {
8658d7f2e76SPhilippe Mathieu-Daudé                 return NULL;
8668d7f2e76SPhilippe Mathieu-Daudé             }
8678d7f2e76SPhilippe Mathieu-Daudé             if (next) {
8688d7f2e76SPhilippe Mathieu-Daudé                 mr = next;
8698d7f2e76SPhilippe Mathieu-Daudé                 continue;
8708d7f2e76SPhilippe Mathieu-Daudé             }
8718d7f2e76SPhilippe Mathieu-Daudé         }
8728d7f2e76SPhilippe Mathieu-Daudé 
8738d7f2e76SPhilippe Mathieu-Daudé         return mr;
8748d7f2e76SPhilippe Mathieu-Daudé     }
8758d7f2e76SPhilippe Mathieu-Daudé 
8768d7f2e76SPhilippe Mathieu-Daudé     return NULL;
8778d7f2e76SPhilippe Mathieu-Daudé }
8788d7f2e76SPhilippe Mathieu-Daudé 
8798d7f2e76SPhilippe Mathieu-Daudé /* Render a memory topology into a list of disjoint absolute ranges. */
generate_memory_topology(MemoryRegion * mr)8808d7f2e76SPhilippe Mathieu-Daudé static FlatView *generate_memory_topology(MemoryRegion *mr)
8818d7f2e76SPhilippe Mathieu-Daudé {
8828d7f2e76SPhilippe Mathieu-Daudé     int i;
8838d7f2e76SPhilippe Mathieu-Daudé     FlatView *view;
8848d7f2e76SPhilippe Mathieu-Daudé 
8858d7f2e76SPhilippe Mathieu-Daudé     view = flatview_new(mr);
8868d7f2e76SPhilippe Mathieu-Daudé 
8878d7f2e76SPhilippe Mathieu-Daudé     if (mr) {
8888d7f2e76SPhilippe Mathieu-Daudé         render_memory_region(view, mr, int128_zero(),
8898d7f2e76SPhilippe Mathieu-Daudé                              addrrange_make(int128_zero(), int128_2_64()),
890533f5d66SDavid Hildenbrand                              false, false, false);
8918d7f2e76SPhilippe Mathieu-Daudé     }
8928d7f2e76SPhilippe Mathieu-Daudé     flatview_simplify(view);
8938d7f2e76SPhilippe Mathieu-Daudé 
8948d7f2e76SPhilippe Mathieu-Daudé     view->dispatch = address_space_dispatch_new(view);
8958d7f2e76SPhilippe Mathieu-Daudé     for (i = 0; i < view->nr; i++) {
8968d7f2e76SPhilippe Mathieu-Daudé         MemoryRegionSection mrs =
8978d7f2e76SPhilippe Mathieu-Daudé             section_from_flat_range(&view->ranges[i], view);
8988d7f2e76SPhilippe Mathieu-Daudé         flatview_add_to_dispatch(view, &mrs);
8998d7f2e76SPhilippe Mathieu-Daudé     }
9008d7f2e76SPhilippe Mathieu-Daudé     address_space_dispatch_compact(view->dispatch);
9018d7f2e76SPhilippe Mathieu-Daudé     g_hash_table_replace(flat_views, mr, view);
9028d7f2e76SPhilippe Mathieu-Daudé 
9038d7f2e76SPhilippe Mathieu-Daudé     return view;
9048d7f2e76SPhilippe Mathieu-Daudé }
9058d7f2e76SPhilippe Mathieu-Daudé 
address_space_add_del_ioeventfds(AddressSpace * as,MemoryRegionIoeventfd * fds_new,unsigned fds_new_nb,MemoryRegionIoeventfd * fds_old,unsigned fds_old_nb)9068d7f2e76SPhilippe Mathieu-Daudé static void address_space_add_del_ioeventfds(AddressSpace *as,
9078d7f2e76SPhilippe Mathieu-Daudé                                              MemoryRegionIoeventfd *fds_new,
9088d7f2e76SPhilippe Mathieu-Daudé                                              unsigned fds_new_nb,
9098d7f2e76SPhilippe Mathieu-Daudé                                              MemoryRegionIoeventfd *fds_old,
9108d7f2e76SPhilippe Mathieu-Daudé                                              unsigned fds_old_nb)
9118d7f2e76SPhilippe Mathieu-Daudé {
9128d7f2e76SPhilippe Mathieu-Daudé     unsigned iold, inew;
9138d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionIoeventfd *fd;
9148d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionSection section;
9158d7f2e76SPhilippe Mathieu-Daudé 
9168d7f2e76SPhilippe Mathieu-Daudé     /* Generate a symmetric difference of the old and new fd sets, adding
9178d7f2e76SPhilippe Mathieu-Daudé      * and deleting as necessary.
9188d7f2e76SPhilippe Mathieu-Daudé      */
9198d7f2e76SPhilippe Mathieu-Daudé 
9208d7f2e76SPhilippe Mathieu-Daudé     iold = inew = 0;
9218d7f2e76SPhilippe Mathieu-Daudé     while (iold < fds_old_nb || inew < fds_new_nb) {
9228d7f2e76SPhilippe Mathieu-Daudé         if (iold < fds_old_nb
9238d7f2e76SPhilippe Mathieu-Daudé             && (inew == fds_new_nb
9248d7f2e76SPhilippe Mathieu-Daudé                 || memory_region_ioeventfd_before(&fds_old[iold],
9258d7f2e76SPhilippe Mathieu-Daudé                                                   &fds_new[inew]))) {
9268d7f2e76SPhilippe Mathieu-Daudé             fd = &fds_old[iold];
9278d7f2e76SPhilippe Mathieu-Daudé             section = (MemoryRegionSection) {
9288d7f2e76SPhilippe Mathieu-Daudé                 .fv = address_space_to_flatview(as),
9298d7f2e76SPhilippe Mathieu-Daudé                 .offset_within_address_space = int128_get64(fd->addr.start),
9308d7f2e76SPhilippe Mathieu-Daudé                 .size = fd->addr.size,
9318d7f2e76SPhilippe Mathieu-Daudé             };
9328d7f2e76SPhilippe Mathieu-Daudé             MEMORY_LISTENER_CALL(as, eventfd_del, Forward, &section,
9338d7f2e76SPhilippe Mathieu-Daudé                                  fd->match_data, fd->data, fd->e);
9348d7f2e76SPhilippe Mathieu-Daudé             ++iold;
9358d7f2e76SPhilippe Mathieu-Daudé         } else if (inew < fds_new_nb
9368d7f2e76SPhilippe Mathieu-Daudé                    && (iold == fds_old_nb
9378d7f2e76SPhilippe Mathieu-Daudé                        || memory_region_ioeventfd_before(&fds_new[inew],
9388d7f2e76SPhilippe Mathieu-Daudé                                                          &fds_old[iold]))) {
9398d7f2e76SPhilippe Mathieu-Daudé             fd = &fds_new[inew];
9408d7f2e76SPhilippe Mathieu-Daudé             section = (MemoryRegionSection) {
9418d7f2e76SPhilippe Mathieu-Daudé                 .fv = address_space_to_flatview(as),
9428d7f2e76SPhilippe Mathieu-Daudé                 .offset_within_address_space = int128_get64(fd->addr.start),
9438d7f2e76SPhilippe Mathieu-Daudé                 .size = fd->addr.size,
9448d7f2e76SPhilippe Mathieu-Daudé             };
9458d7f2e76SPhilippe Mathieu-Daudé             MEMORY_LISTENER_CALL(as, eventfd_add, Reverse, &section,
9468d7f2e76SPhilippe Mathieu-Daudé                                  fd->match_data, fd->data, fd->e);
9478d7f2e76SPhilippe Mathieu-Daudé             ++inew;
9488d7f2e76SPhilippe Mathieu-Daudé         } else {
9498d7f2e76SPhilippe Mathieu-Daudé             ++iold;
9508d7f2e76SPhilippe Mathieu-Daudé             ++inew;
9518d7f2e76SPhilippe Mathieu-Daudé         }
9528d7f2e76SPhilippe Mathieu-Daudé     }
9538d7f2e76SPhilippe Mathieu-Daudé }
9548d7f2e76SPhilippe Mathieu-Daudé 
address_space_get_flatview(AddressSpace * as)9558d7f2e76SPhilippe Mathieu-Daudé FlatView *address_space_get_flatview(AddressSpace *as)
9568d7f2e76SPhilippe Mathieu-Daudé {
9578d7f2e76SPhilippe Mathieu-Daudé     FlatView *view;
9588d7f2e76SPhilippe Mathieu-Daudé 
9598d7f2e76SPhilippe Mathieu-Daudé     RCU_READ_LOCK_GUARD();
9608d7f2e76SPhilippe Mathieu-Daudé     do {
9618d7f2e76SPhilippe Mathieu-Daudé         view = address_space_to_flatview(as);
9628d7f2e76SPhilippe Mathieu-Daudé         /* If somebody has replaced as->current_map concurrently,
9638d7f2e76SPhilippe Mathieu-Daudé          * flatview_ref returns false.
9648d7f2e76SPhilippe Mathieu-Daudé          */
9658d7f2e76SPhilippe Mathieu-Daudé     } while (!flatview_ref(view));
9668d7f2e76SPhilippe Mathieu-Daudé     return view;
9678d7f2e76SPhilippe Mathieu-Daudé }
9688d7f2e76SPhilippe Mathieu-Daudé 
address_space_update_ioeventfds(AddressSpace * as)9698d7f2e76SPhilippe Mathieu-Daudé static void address_space_update_ioeventfds(AddressSpace *as)
9708d7f2e76SPhilippe Mathieu-Daudé {
9718d7f2e76SPhilippe Mathieu-Daudé     FlatView *view;
9728d7f2e76SPhilippe Mathieu-Daudé     FlatRange *fr;
9738d7f2e76SPhilippe Mathieu-Daudé     unsigned ioeventfd_nb = 0;
9748d7f2e76SPhilippe Mathieu-Daudé     unsigned ioeventfd_max;
9758d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionIoeventfd *ioeventfds;
9768d7f2e76SPhilippe Mathieu-Daudé     AddrRange tmp;
9778d7f2e76SPhilippe Mathieu-Daudé     unsigned i;
9788d7f2e76SPhilippe Mathieu-Daudé 
9798d7f2e76SPhilippe Mathieu-Daudé     if (!as->ioeventfd_notifiers) {
9808d7f2e76SPhilippe Mathieu-Daudé         return;
9818d7f2e76SPhilippe Mathieu-Daudé     }
9828d7f2e76SPhilippe Mathieu-Daudé 
9838d7f2e76SPhilippe Mathieu-Daudé     /*
9848d7f2e76SPhilippe Mathieu-Daudé      * It is likely that the number of ioeventfds hasn't changed much, so use
9858d7f2e76SPhilippe Mathieu-Daudé      * the previous size as the starting value, with some headroom to avoid
9868d7f2e76SPhilippe Mathieu-Daudé      * gratuitous reallocations.
9878d7f2e76SPhilippe Mathieu-Daudé      */
9888d7f2e76SPhilippe Mathieu-Daudé     ioeventfd_max = QEMU_ALIGN_UP(as->ioeventfd_nb, 4);
9898d7f2e76SPhilippe Mathieu-Daudé     ioeventfds = g_new(MemoryRegionIoeventfd, ioeventfd_max);
9908d7f2e76SPhilippe Mathieu-Daudé 
9918d7f2e76SPhilippe Mathieu-Daudé     view = address_space_get_flatview(as);
9928d7f2e76SPhilippe Mathieu-Daudé     FOR_EACH_FLAT_RANGE(fr, view) {
9938d7f2e76SPhilippe Mathieu-Daudé         for (i = 0; i < fr->mr->ioeventfd_nb; ++i) {
9948d7f2e76SPhilippe Mathieu-Daudé             tmp = addrrange_shift(fr->mr->ioeventfds[i].addr,
9958d7f2e76SPhilippe Mathieu-Daudé                                   int128_sub(fr->addr.start,
9968d7f2e76SPhilippe Mathieu-Daudé                                              int128_make64(fr->offset_in_region)));
9978d7f2e76SPhilippe Mathieu-Daudé             if (addrrange_intersects(fr->addr, tmp)) {
9988d7f2e76SPhilippe Mathieu-Daudé                 ++ioeventfd_nb;
9998d7f2e76SPhilippe Mathieu-Daudé                 if (ioeventfd_nb > ioeventfd_max) {
10008d7f2e76SPhilippe Mathieu-Daudé                     ioeventfd_max = MAX(ioeventfd_max * 2, 4);
10018d7f2e76SPhilippe Mathieu-Daudé                     ioeventfds = g_realloc(ioeventfds,
10028d7f2e76SPhilippe Mathieu-Daudé                             ioeventfd_max * sizeof(*ioeventfds));
10038d7f2e76SPhilippe Mathieu-Daudé                 }
10048d7f2e76SPhilippe Mathieu-Daudé                 ioeventfds[ioeventfd_nb-1] = fr->mr->ioeventfds[i];
10058d7f2e76SPhilippe Mathieu-Daudé                 ioeventfds[ioeventfd_nb-1].addr = tmp;
10068d7f2e76SPhilippe Mathieu-Daudé             }
10078d7f2e76SPhilippe Mathieu-Daudé         }
10088d7f2e76SPhilippe Mathieu-Daudé     }
10098d7f2e76SPhilippe Mathieu-Daudé 
10108d7f2e76SPhilippe Mathieu-Daudé     address_space_add_del_ioeventfds(as, ioeventfds, ioeventfd_nb,
10118d7f2e76SPhilippe Mathieu-Daudé                                      as->ioeventfds, as->ioeventfd_nb);
10128d7f2e76SPhilippe Mathieu-Daudé 
10138d7f2e76SPhilippe Mathieu-Daudé     g_free(as->ioeventfds);
10148d7f2e76SPhilippe Mathieu-Daudé     as->ioeventfds = ioeventfds;
10158d7f2e76SPhilippe Mathieu-Daudé     as->ioeventfd_nb = ioeventfd_nb;
10168d7f2e76SPhilippe Mathieu-Daudé     flatview_unref(view);
10178d7f2e76SPhilippe Mathieu-Daudé }
10188d7f2e76SPhilippe Mathieu-Daudé 
10198d7f2e76SPhilippe Mathieu-Daudé /*
10208d7f2e76SPhilippe Mathieu-Daudé  * Notify the memory listeners about the coalesced IO change events of
10218d7f2e76SPhilippe Mathieu-Daudé  * range `cmr'.  Only the part that has intersection of the specified
10228d7f2e76SPhilippe Mathieu-Daudé  * FlatRange will be sent.
10238d7f2e76SPhilippe Mathieu-Daudé  */
flat_range_coalesced_io_notify(FlatRange * fr,AddressSpace * as,CoalescedMemoryRange * cmr,bool add)10248d7f2e76SPhilippe Mathieu-Daudé static void flat_range_coalesced_io_notify(FlatRange *fr, AddressSpace *as,
10258d7f2e76SPhilippe Mathieu-Daudé                                            CoalescedMemoryRange *cmr, bool add)
10268d7f2e76SPhilippe Mathieu-Daudé {
10278d7f2e76SPhilippe Mathieu-Daudé     AddrRange tmp;
10288d7f2e76SPhilippe Mathieu-Daudé 
10298d7f2e76SPhilippe Mathieu-Daudé     tmp = addrrange_shift(cmr->addr,
10308d7f2e76SPhilippe Mathieu-Daudé                           int128_sub(fr->addr.start,
10318d7f2e76SPhilippe Mathieu-Daudé                                      int128_make64(fr->offset_in_region)));
10328d7f2e76SPhilippe Mathieu-Daudé     if (!addrrange_intersects(tmp, fr->addr)) {
10338d7f2e76SPhilippe Mathieu-Daudé         return;
10348d7f2e76SPhilippe Mathieu-Daudé     }
10358d7f2e76SPhilippe Mathieu-Daudé     tmp = addrrange_intersection(tmp, fr->addr);
10368d7f2e76SPhilippe Mathieu-Daudé 
10378d7f2e76SPhilippe Mathieu-Daudé     if (add) {
10388d7f2e76SPhilippe Mathieu-Daudé         MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, coalesced_io_add,
10398d7f2e76SPhilippe Mathieu-Daudé                                       int128_get64(tmp.start),
10408d7f2e76SPhilippe Mathieu-Daudé                                       int128_get64(tmp.size));
10418d7f2e76SPhilippe Mathieu-Daudé     } else {
10428d7f2e76SPhilippe Mathieu-Daudé         MEMORY_LISTENER_UPDATE_REGION(fr, as, Reverse, coalesced_io_del,
10438d7f2e76SPhilippe Mathieu-Daudé                                       int128_get64(tmp.start),
10448d7f2e76SPhilippe Mathieu-Daudé                                       int128_get64(tmp.size));
10458d7f2e76SPhilippe Mathieu-Daudé     }
10468d7f2e76SPhilippe Mathieu-Daudé }
10478d7f2e76SPhilippe Mathieu-Daudé 
flat_range_coalesced_io_del(FlatRange * fr,AddressSpace * as)10488d7f2e76SPhilippe Mathieu-Daudé static void flat_range_coalesced_io_del(FlatRange *fr, AddressSpace *as)
10498d7f2e76SPhilippe Mathieu-Daudé {
10508d7f2e76SPhilippe Mathieu-Daudé     CoalescedMemoryRange *cmr;
10518d7f2e76SPhilippe Mathieu-Daudé 
10528d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(cmr, &fr->mr->coalesced, link) {
10538d7f2e76SPhilippe Mathieu-Daudé         flat_range_coalesced_io_notify(fr, as, cmr, false);
10548d7f2e76SPhilippe Mathieu-Daudé     }
10558d7f2e76SPhilippe Mathieu-Daudé }
10568d7f2e76SPhilippe Mathieu-Daudé 
flat_range_coalesced_io_add(FlatRange * fr,AddressSpace * as)10578d7f2e76SPhilippe Mathieu-Daudé static void flat_range_coalesced_io_add(FlatRange *fr, AddressSpace *as)
10588d7f2e76SPhilippe Mathieu-Daudé {
10598d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr = fr->mr;
10608d7f2e76SPhilippe Mathieu-Daudé     CoalescedMemoryRange *cmr;
10618d7f2e76SPhilippe Mathieu-Daudé 
10628d7f2e76SPhilippe Mathieu-Daudé     if (QTAILQ_EMPTY(&mr->coalesced)) {
10638d7f2e76SPhilippe Mathieu-Daudé         return;
10648d7f2e76SPhilippe Mathieu-Daudé     }
10658d7f2e76SPhilippe Mathieu-Daudé 
10668d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(cmr, &mr->coalesced, link) {
10678d7f2e76SPhilippe Mathieu-Daudé         flat_range_coalesced_io_notify(fr, as, cmr, true);
10688d7f2e76SPhilippe Mathieu-Daudé     }
10698d7f2e76SPhilippe Mathieu-Daudé }
10708d7f2e76SPhilippe Mathieu-Daudé 
10718d3031faSAni Sinha static void
flat_range_coalesced_io_notify_listener_add_del(FlatRange * fr,MemoryRegionSection * mrs,MemoryListener * listener,AddressSpace * as,bool add)10728d3031faSAni Sinha flat_range_coalesced_io_notify_listener_add_del(FlatRange *fr,
10738d3031faSAni Sinha                                                 MemoryRegionSection *mrs,
10748d3031faSAni Sinha                                                 MemoryListener *listener,
10758d3031faSAni Sinha                                                 AddressSpace *as, bool add)
10768d3031faSAni Sinha {
10778d3031faSAni Sinha     CoalescedMemoryRange *cmr;
10788d3031faSAni Sinha     MemoryRegion *mr = fr->mr;
10798d3031faSAni Sinha     AddrRange tmp;
10808d3031faSAni Sinha 
10818d3031faSAni Sinha     QTAILQ_FOREACH(cmr, &mr->coalesced, link) {
10828d3031faSAni Sinha         tmp = addrrange_shift(cmr->addr,
10838d3031faSAni Sinha                               int128_sub(fr->addr.start,
10848d3031faSAni Sinha                                          int128_make64(fr->offset_in_region)));
10858d3031faSAni Sinha 
10868d3031faSAni Sinha         if (!addrrange_intersects(tmp, fr->addr)) {
10878d3031faSAni Sinha             return;
10888d3031faSAni Sinha         }
10898d3031faSAni Sinha         tmp = addrrange_intersection(tmp, fr->addr);
10908d3031faSAni Sinha 
10918d3031faSAni Sinha         if (add && listener->coalesced_io_add) {
10928d3031faSAni Sinha             listener->coalesced_io_add(listener, mrs,
10938d3031faSAni Sinha                                        int128_get64(tmp.start),
10948d3031faSAni Sinha                                        int128_get64(tmp.size));
10958d3031faSAni Sinha         } else if (!add && listener->coalesced_io_del) {
10968d3031faSAni Sinha             listener->coalesced_io_del(listener, mrs,
10978d3031faSAni Sinha                                        int128_get64(tmp.start),
10988d3031faSAni Sinha                                        int128_get64(tmp.size));
10998d3031faSAni Sinha         }
11008d3031faSAni Sinha     }
11018d3031faSAni Sinha }
11028d3031faSAni Sinha 
address_space_update_topology_pass(AddressSpace * as,const FlatView * old_view,const FlatView * new_view,bool adding)11038d7f2e76SPhilippe Mathieu-Daudé static void address_space_update_topology_pass(AddressSpace *as,
11048d7f2e76SPhilippe Mathieu-Daudé                                                const FlatView *old_view,
11058d7f2e76SPhilippe Mathieu-Daudé                                                const FlatView *new_view,
11068d7f2e76SPhilippe Mathieu-Daudé                                                bool adding)
11078d7f2e76SPhilippe Mathieu-Daudé {
11088d7f2e76SPhilippe Mathieu-Daudé     unsigned iold, inew;
11098d7f2e76SPhilippe Mathieu-Daudé     FlatRange *frold, *frnew;
11108d7f2e76SPhilippe Mathieu-Daudé 
11118d7f2e76SPhilippe Mathieu-Daudé     /* Generate a symmetric difference of the old and new memory maps.
11128d7f2e76SPhilippe Mathieu-Daudé      * Kill ranges in the old map, and instantiate ranges in the new map.
11138d7f2e76SPhilippe Mathieu-Daudé      */
11148d7f2e76SPhilippe Mathieu-Daudé     iold = inew = 0;
11158d7f2e76SPhilippe Mathieu-Daudé     while (iold < old_view->nr || inew < new_view->nr) {
11168d7f2e76SPhilippe Mathieu-Daudé         if (iold < old_view->nr) {
11178d7f2e76SPhilippe Mathieu-Daudé             frold = &old_view->ranges[iold];
11188d7f2e76SPhilippe Mathieu-Daudé         } else {
11198d7f2e76SPhilippe Mathieu-Daudé             frold = NULL;
11208d7f2e76SPhilippe Mathieu-Daudé         }
11218d7f2e76SPhilippe Mathieu-Daudé         if (inew < new_view->nr) {
11228d7f2e76SPhilippe Mathieu-Daudé             frnew = &new_view->ranges[inew];
11238d7f2e76SPhilippe Mathieu-Daudé         } else {
11248d7f2e76SPhilippe Mathieu-Daudé             frnew = NULL;
11258d7f2e76SPhilippe Mathieu-Daudé         }
11268d7f2e76SPhilippe Mathieu-Daudé 
11278d7f2e76SPhilippe Mathieu-Daudé         if (frold
11288d7f2e76SPhilippe Mathieu-Daudé             && (!frnew
11298d7f2e76SPhilippe Mathieu-Daudé                 || int128_lt(frold->addr.start, frnew->addr.start)
11308d7f2e76SPhilippe Mathieu-Daudé                 || (int128_eq(frold->addr.start, frnew->addr.start)
11318d7f2e76SPhilippe Mathieu-Daudé                     && !flatrange_equal(frold, frnew)))) {
11328d7f2e76SPhilippe Mathieu-Daudé             /* In old but not in new, or in both but attributes changed. */
11338d7f2e76SPhilippe Mathieu-Daudé 
11348d7f2e76SPhilippe Mathieu-Daudé             if (!adding) {
11358d7f2e76SPhilippe Mathieu-Daudé                 flat_range_coalesced_io_del(frold, as);
11368d7f2e76SPhilippe Mathieu-Daudé                 MEMORY_LISTENER_UPDATE_REGION(frold, as, Reverse, region_del);
11378d7f2e76SPhilippe Mathieu-Daudé             }
11388d7f2e76SPhilippe Mathieu-Daudé 
11398d7f2e76SPhilippe Mathieu-Daudé             ++iold;
11408d7f2e76SPhilippe Mathieu-Daudé         } else if (frold && frnew && flatrange_equal(frold, frnew)) {
11418d7f2e76SPhilippe Mathieu-Daudé             /* In both and unchanged (except logging may have changed) */
11428d7f2e76SPhilippe Mathieu-Daudé 
11438d7f2e76SPhilippe Mathieu-Daudé             if (adding) {
11448d7f2e76SPhilippe Mathieu-Daudé                 MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, region_nop);
11458d7f2e76SPhilippe Mathieu-Daudé                 if (frnew->dirty_log_mask & ~frold->dirty_log_mask) {
11468d7f2e76SPhilippe Mathieu-Daudé                     MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, log_start,
11478d7f2e76SPhilippe Mathieu-Daudé                                                   frold->dirty_log_mask,
11488d7f2e76SPhilippe Mathieu-Daudé                                                   frnew->dirty_log_mask);
11498d7f2e76SPhilippe Mathieu-Daudé                 }
11508d7f2e76SPhilippe Mathieu-Daudé                 if (frold->dirty_log_mask & ~frnew->dirty_log_mask) {
11518d7f2e76SPhilippe Mathieu-Daudé                     MEMORY_LISTENER_UPDATE_REGION(frnew, as, Reverse, log_stop,
11528d7f2e76SPhilippe Mathieu-Daudé                                                   frold->dirty_log_mask,
11538d7f2e76SPhilippe Mathieu-Daudé                                                   frnew->dirty_log_mask);
11548d7f2e76SPhilippe Mathieu-Daudé                 }
11558d7f2e76SPhilippe Mathieu-Daudé             }
11568d7f2e76SPhilippe Mathieu-Daudé 
11578d7f2e76SPhilippe Mathieu-Daudé             ++iold;
11588d7f2e76SPhilippe Mathieu-Daudé             ++inew;
11598d7f2e76SPhilippe Mathieu-Daudé         } else {
11608d7f2e76SPhilippe Mathieu-Daudé             /* In new */
11618d7f2e76SPhilippe Mathieu-Daudé 
11628d7f2e76SPhilippe Mathieu-Daudé             if (adding) {
11638d7f2e76SPhilippe Mathieu-Daudé                 MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, region_add);
11648d7f2e76SPhilippe Mathieu-Daudé                 flat_range_coalesced_io_add(frnew, as);
11658d7f2e76SPhilippe Mathieu-Daudé             }
11668d7f2e76SPhilippe Mathieu-Daudé 
11678d7f2e76SPhilippe Mathieu-Daudé             ++inew;
11688d7f2e76SPhilippe Mathieu-Daudé         }
11698d7f2e76SPhilippe Mathieu-Daudé     }
11708d7f2e76SPhilippe Mathieu-Daudé }
11718d7f2e76SPhilippe Mathieu-Daudé 
flatviews_init(void)11728d7f2e76SPhilippe Mathieu-Daudé static void flatviews_init(void)
11738d7f2e76SPhilippe Mathieu-Daudé {
11748d7f2e76SPhilippe Mathieu-Daudé     static FlatView *empty_view;
11758d7f2e76SPhilippe Mathieu-Daudé 
11768d7f2e76SPhilippe Mathieu-Daudé     if (flat_views) {
11778d7f2e76SPhilippe Mathieu-Daudé         return;
11788d7f2e76SPhilippe Mathieu-Daudé     }
11798d7f2e76SPhilippe Mathieu-Daudé 
11808d7f2e76SPhilippe Mathieu-Daudé     flat_views = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
11818d7f2e76SPhilippe Mathieu-Daudé                                        (GDestroyNotify) flatview_unref);
11828d7f2e76SPhilippe Mathieu-Daudé     if (!empty_view) {
11838d7f2e76SPhilippe Mathieu-Daudé         empty_view = generate_memory_topology(NULL);
11848d7f2e76SPhilippe Mathieu-Daudé         /* We keep it alive forever in the global variable.  */
11858d7f2e76SPhilippe Mathieu-Daudé         flatview_ref(empty_view);
11868d7f2e76SPhilippe Mathieu-Daudé     } else {
11878d7f2e76SPhilippe Mathieu-Daudé         g_hash_table_replace(flat_views, NULL, empty_view);
11888d7f2e76SPhilippe Mathieu-Daudé         flatview_ref(empty_view);
11898d7f2e76SPhilippe Mathieu-Daudé     }
11908d7f2e76SPhilippe Mathieu-Daudé }
11918d7f2e76SPhilippe Mathieu-Daudé 
flatviews_reset(void)11928d7f2e76SPhilippe Mathieu-Daudé static void flatviews_reset(void)
11938d7f2e76SPhilippe Mathieu-Daudé {
11948d7f2e76SPhilippe Mathieu-Daudé     AddressSpace *as;
11958d7f2e76SPhilippe Mathieu-Daudé 
11968d7f2e76SPhilippe Mathieu-Daudé     if (flat_views) {
11978d7f2e76SPhilippe Mathieu-Daudé         g_hash_table_unref(flat_views);
11988d7f2e76SPhilippe Mathieu-Daudé         flat_views = NULL;
11998d7f2e76SPhilippe Mathieu-Daudé     }
12008d7f2e76SPhilippe Mathieu-Daudé     flatviews_init();
12018d7f2e76SPhilippe Mathieu-Daudé 
12028d7f2e76SPhilippe Mathieu-Daudé     /* Render unique FVs */
12038d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
12048d7f2e76SPhilippe Mathieu-Daudé         MemoryRegion *physmr = memory_region_get_flatview_root(as->root);
12058d7f2e76SPhilippe Mathieu-Daudé 
12068d7f2e76SPhilippe Mathieu-Daudé         if (g_hash_table_lookup(flat_views, physmr)) {
12078d7f2e76SPhilippe Mathieu-Daudé             continue;
12088d7f2e76SPhilippe Mathieu-Daudé         }
12098d7f2e76SPhilippe Mathieu-Daudé 
12108d7f2e76SPhilippe Mathieu-Daudé         generate_memory_topology(physmr);
12118d7f2e76SPhilippe Mathieu-Daudé     }
12128d7f2e76SPhilippe Mathieu-Daudé }
12138d7f2e76SPhilippe Mathieu-Daudé 
address_space_set_flatview(AddressSpace * as)12148d7f2e76SPhilippe Mathieu-Daudé static void address_space_set_flatview(AddressSpace *as)
12158d7f2e76SPhilippe Mathieu-Daudé {
12168d7f2e76SPhilippe Mathieu-Daudé     FlatView *old_view = address_space_to_flatview(as);
12178d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *physmr = memory_region_get_flatview_root(as->root);
12188d7f2e76SPhilippe Mathieu-Daudé     FlatView *new_view = g_hash_table_lookup(flat_views, physmr);
12198d7f2e76SPhilippe Mathieu-Daudé 
12208d7f2e76SPhilippe Mathieu-Daudé     assert(new_view);
12218d7f2e76SPhilippe Mathieu-Daudé 
12228d7f2e76SPhilippe Mathieu-Daudé     if (old_view == new_view) {
12238d7f2e76SPhilippe Mathieu-Daudé         return;
12248d7f2e76SPhilippe Mathieu-Daudé     }
12258d7f2e76SPhilippe Mathieu-Daudé 
12268d7f2e76SPhilippe Mathieu-Daudé     if (old_view) {
12278d7f2e76SPhilippe Mathieu-Daudé         flatview_ref(old_view);
12288d7f2e76SPhilippe Mathieu-Daudé     }
12298d7f2e76SPhilippe Mathieu-Daudé 
12308d7f2e76SPhilippe Mathieu-Daudé     flatview_ref(new_view);
12318d7f2e76SPhilippe Mathieu-Daudé 
12328d7f2e76SPhilippe Mathieu-Daudé     if (!QTAILQ_EMPTY(&as->listeners)) {
12338d7f2e76SPhilippe Mathieu-Daudé         FlatView tmpview = { .nr = 0 }, *old_view2 = old_view;
12348d7f2e76SPhilippe Mathieu-Daudé 
12358d7f2e76SPhilippe Mathieu-Daudé         if (!old_view2) {
12368d7f2e76SPhilippe Mathieu-Daudé             old_view2 = &tmpview;
12378d7f2e76SPhilippe Mathieu-Daudé         }
12388d7f2e76SPhilippe Mathieu-Daudé         address_space_update_topology_pass(as, old_view2, new_view, false);
12398d7f2e76SPhilippe Mathieu-Daudé         address_space_update_topology_pass(as, old_view2, new_view, true);
12408d7f2e76SPhilippe Mathieu-Daudé     }
12418d7f2e76SPhilippe Mathieu-Daudé 
12428d7f2e76SPhilippe Mathieu-Daudé     /* Writes are protected by the BQL.  */
12438d7f2e76SPhilippe Mathieu-Daudé     qatomic_rcu_set(&as->current_map, new_view);
12448d7f2e76SPhilippe Mathieu-Daudé     if (old_view) {
12458d7f2e76SPhilippe Mathieu-Daudé         flatview_unref(old_view);
12468d7f2e76SPhilippe Mathieu-Daudé     }
12478d7f2e76SPhilippe Mathieu-Daudé 
12488d7f2e76SPhilippe Mathieu-Daudé     /* Note that all the old MemoryRegions are still alive up to this
12498d7f2e76SPhilippe Mathieu-Daudé      * point.  This relieves most MemoryListeners from the need to
12508d7f2e76SPhilippe Mathieu-Daudé      * ref/unref the MemoryRegions they get---unless they use them
12518d7f2e76SPhilippe Mathieu-Daudé      * outside the iothread mutex, in which case precise reference
12528d7f2e76SPhilippe Mathieu-Daudé      * counting is necessary.
12538d7f2e76SPhilippe Mathieu-Daudé      */
12548d7f2e76SPhilippe Mathieu-Daudé     if (old_view) {
12558d7f2e76SPhilippe Mathieu-Daudé         flatview_unref(old_view);
12568d7f2e76SPhilippe Mathieu-Daudé     }
12578d7f2e76SPhilippe Mathieu-Daudé }
12588d7f2e76SPhilippe Mathieu-Daudé 
address_space_update_topology(AddressSpace * as)12598d7f2e76SPhilippe Mathieu-Daudé static void address_space_update_topology(AddressSpace *as)
12608d7f2e76SPhilippe Mathieu-Daudé {
12618d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *physmr = memory_region_get_flatview_root(as->root);
12628d7f2e76SPhilippe Mathieu-Daudé 
12638d7f2e76SPhilippe Mathieu-Daudé     flatviews_init();
12648d7f2e76SPhilippe Mathieu-Daudé     if (!g_hash_table_lookup(flat_views, physmr)) {
12658d7f2e76SPhilippe Mathieu-Daudé         generate_memory_topology(physmr);
12668d7f2e76SPhilippe Mathieu-Daudé     }
12678d7f2e76SPhilippe Mathieu-Daudé     address_space_set_flatview(as);
12688d7f2e76SPhilippe Mathieu-Daudé }
12698d7f2e76SPhilippe Mathieu-Daudé 
memory_region_transaction_begin(void)12708d7f2e76SPhilippe Mathieu-Daudé void memory_region_transaction_begin(void)
12718d7f2e76SPhilippe Mathieu-Daudé {
12728d7f2e76SPhilippe Mathieu-Daudé     qemu_flush_coalesced_mmio_buffer();
12738d7f2e76SPhilippe Mathieu-Daudé     ++memory_region_transaction_depth;
12748d7f2e76SPhilippe Mathieu-Daudé }
12758d7f2e76SPhilippe Mathieu-Daudé 
memory_region_transaction_commit(void)12768d7f2e76SPhilippe Mathieu-Daudé void memory_region_transaction_commit(void)
12778d7f2e76SPhilippe Mathieu-Daudé {
12788d7f2e76SPhilippe Mathieu-Daudé     AddressSpace *as;
12798d7f2e76SPhilippe Mathieu-Daudé 
12808d7f2e76SPhilippe Mathieu-Daudé     assert(memory_region_transaction_depth);
1281195801d7SStefan Hajnoczi     assert(bql_locked());
12828d7f2e76SPhilippe Mathieu-Daudé 
12838d7f2e76SPhilippe Mathieu-Daudé     --memory_region_transaction_depth;
12848d7f2e76SPhilippe Mathieu-Daudé     if (!memory_region_transaction_depth) {
12858d7f2e76SPhilippe Mathieu-Daudé         if (memory_region_update_pending) {
12868d7f2e76SPhilippe Mathieu-Daudé             flatviews_reset();
12878d7f2e76SPhilippe Mathieu-Daudé 
12888d7f2e76SPhilippe Mathieu-Daudé             MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
12898d7f2e76SPhilippe Mathieu-Daudé 
12908d7f2e76SPhilippe Mathieu-Daudé             QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
12918d7f2e76SPhilippe Mathieu-Daudé                 address_space_set_flatview(as);
12928d7f2e76SPhilippe Mathieu-Daudé                 address_space_update_ioeventfds(as);
12938d7f2e76SPhilippe Mathieu-Daudé             }
12948d7f2e76SPhilippe Mathieu-Daudé             memory_region_update_pending = false;
12958d7f2e76SPhilippe Mathieu-Daudé             ioeventfd_update_pending = false;
12968d7f2e76SPhilippe Mathieu-Daudé             MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
12978d7f2e76SPhilippe Mathieu-Daudé         } else if (ioeventfd_update_pending) {
12988d7f2e76SPhilippe Mathieu-Daudé             QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
12998d7f2e76SPhilippe Mathieu-Daudé                 address_space_update_ioeventfds(as);
13008d7f2e76SPhilippe Mathieu-Daudé             }
13018d7f2e76SPhilippe Mathieu-Daudé             ioeventfd_update_pending = false;
13028d7f2e76SPhilippe Mathieu-Daudé         }
13038d7f2e76SPhilippe Mathieu-Daudé    }
13048d7f2e76SPhilippe Mathieu-Daudé }
13058d7f2e76SPhilippe Mathieu-Daudé 
memory_region_destructor_none(MemoryRegion * mr)13068d7f2e76SPhilippe Mathieu-Daudé static void memory_region_destructor_none(MemoryRegion *mr)
13078d7f2e76SPhilippe Mathieu-Daudé {
13088d7f2e76SPhilippe Mathieu-Daudé }
13098d7f2e76SPhilippe Mathieu-Daudé 
memory_region_destructor_ram(MemoryRegion * mr)13108d7f2e76SPhilippe Mathieu-Daudé static void memory_region_destructor_ram(MemoryRegion *mr)
13118d7f2e76SPhilippe Mathieu-Daudé {
13128d7f2e76SPhilippe Mathieu-Daudé     qemu_ram_free(mr->ram_block);
13138d7f2e76SPhilippe Mathieu-Daudé }
13148d7f2e76SPhilippe Mathieu-Daudé 
memory_region_need_escape(char c)13158d7f2e76SPhilippe Mathieu-Daudé static bool memory_region_need_escape(char c)
13168d7f2e76SPhilippe Mathieu-Daudé {
13178d7f2e76SPhilippe Mathieu-Daudé     return c == '/' || c == '[' || c == '\\' || c == ']';
13188d7f2e76SPhilippe Mathieu-Daudé }
13198d7f2e76SPhilippe Mathieu-Daudé 
memory_region_escape_name(const char * name)13208d7f2e76SPhilippe Mathieu-Daudé static char *memory_region_escape_name(const char *name)
13218d7f2e76SPhilippe Mathieu-Daudé {
13228d7f2e76SPhilippe Mathieu-Daudé     const char *p;
13238d7f2e76SPhilippe Mathieu-Daudé     char *escaped, *q;
13248d7f2e76SPhilippe Mathieu-Daudé     uint8_t c;
13258d7f2e76SPhilippe Mathieu-Daudé     size_t bytes = 0;
13268d7f2e76SPhilippe Mathieu-Daudé 
13278d7f2e76SPhilippe Mathieu-Daudé     for (p = name; *p; p++) {
13288d7f2e76SPhilippe Mathieu-Daudé         bytes += memory_region_need_escape(*p) ? 4 : 1;
13298d7f2e76SPhilippe Mathieu-Daudé     }
13308d7f2e76SPhilippe Mathieu-Daudé     if (bytes == p - name) {
13318d7f2e76SPhilippe Mathieu-Daudé        return g_memdup(name, bytes + 1);
13328d7f2e76SPhilippe Mathieu-Daudé     }
13338d7f2e76SPhilippe Mathieu-Daudé 
13348d7f2e76SPhilippe Mathieu-Daudé     escaped = g_malloc(bytes + 1);
13358d7f2e76SPhilippe Mathieu-Daudé     for (p = name, q = escaped; *p; p++) {
13368d7f2e76SPhilippe Mathieu-Daudé         c = *p;
13378d7f2e76SPhilippe Mathieu-Daudé         if (unlikely(memory_region_need_escape(c))) {
13388d7f2e76SPhilippe Mathieu-Daudé             *q++ = '\\';
13398d7f2e76SPhilippe Mathieu-Daudé             *q++ = 'x';
13408d7f2e76SPhilippe Mathieu-Daudé             *q++ = "0123456789abcdef"[c >> 4];
13418d7f2e76SPhilippe Mathieu-Daudé             c = "0123456789abcdef"[c & 15];
13428d7f2e76SPhilippe Mathieu-Daudé         }
13438d7f2e76SPhilippe Mathieu-Daudé         *q++ = c;
13448d7f2e76SPhilippe Mathieu-Daudé     }
13458d7f2e76SPhilippe Mathieu-Daudé     *q = 0;
13468d7f2e76SPhilippe Mathieu-Daudé     return escaped;
13478d7f2e76SPhilippe Mathieu-Daudé }
13488d7f2e76SPhilippe Mathieu-Daudé 
memory_region_do_init(MemoryRegion * mr,Object * owner,const char * name,uint64_t size)13498d7f2e76SPhilippe Mathieu-Daudé static void memory_region_do_init(MemoryRegion *mr,
13508d7f2e76SPhilippe Mathieu-Daudé                                   Object *owner,
13518d7f2e76SPhilippe Mathieu-Daudé                                   const char *name,
13528d7f2e76SPhilippe Mathieu-Daudé                                   uint64_t size)
13538d7f2e76SPhilippe Mathieu-Daudé {
13548d7f2e76SPhilippe Mathieu-Daudé     mr->size = int128_make64(size);
13558d7f2e76SPhilippe Mathieu-Daudé     if (size == UINT64_MAX) {
13568d7f2e76SPhilippe Mathieu-Daudé         mr->size = int128_2_64();
13578d7f2e76SPhilippe Mathieu-Daudé     }
13588d7f2e76SPhilippe Mathieu-Daudé     mr->name = g_strdup(name);
13598d7f2e76SPhilippe Mathieu-Daudé     mr->owner = owner;
13608d7f2e76SPhilippe Mathieu-Daudé     mr->dev = (DeviceState *) object_dynamic_cast(mr->owner, TYPE_DEVICE);
13618d7f2e76SPhilippe Mathieu-Daudé     mr->ram_block = NULL;
13628d7f2e76SPhilippe Mathieu-Daudé 
13638d7f2e76SPhilippe Mathieu-Daudé     if (name) {
13648d7f2e76SPhilippe Mathieu-Daudé         char *escaped_name = memory_region_escape_name(name);
13658d7f2e76SPhilippe Mathieu-Daudé         char *name_array = g_strdup_printf("%s[*]", escaped_name);
13668d7f2e76SPhilippe Mathieu-Daudé 
13678d7f2e76SPhilippe Mathieu-Daudé         if (!owner) {
13688d7f2e76SPhilippe Mathieu-Daudé             owner = container_get(qdev_get_machine(), "/unattached");
13698d7f2e76SPhilippe Mathieu-Daudé         }
13708d7f2e76SPhilippe Mathieu-Daudé 
13718d7f2e76SPhilippe Mathieu-Daudé         object_property_add_child(owner, name_array, OBJECT(mr));
13728d7f2e76SPhilippe Mathieu-Daudé         object_unref(OBJECT(mr));
13738d7f2e76SPhilippe Mathieu-Daudé         g_free(name_array);
13748d7f2e76SPhilippe Mathieu-Daudé         g_free(escaped_name);
13758d7f2e76SPhilippe Mathieu-Daudé     }
13768d7f2e76SPhilippe Mathieu-Daudé }
13778d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init(MemoryRegion * mr,Object * owner,const char * name,uint64_t size)13788d7f2e76SPhilippe Mathieu-Daudé void memory_region_init(MemoryRegion *mr,
13798d7f2e76SPhilippe Mathieu-Daudé                         Object *owner,
13808d7f2e76SPhilippe Mathieu-Daudé                         const char *name,
13818d7f2e76SPhilippe Mathieu-Daudé                         uint64_t size)
13828d7f2e76SPhilippe Mathieu-Daudé {
13838d7f2e76SPhilippe Mathieu-Daudé     object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
13848d7f2e76SPhilippe Mathieu-Daudé     memory_region_do_init(mr, owner, name, size);
13858d7f2e76SPhilippe Mathieu-Daudé }
13868d7f2e76SPhilippe Mathieu-Daudé 
memory_region_get_container(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)13878d7f2e76SPhilippe Mathieu-Daudé static void memory_region_get_container(Object *obj, Visitor *v,
13888d7f2e76SPhilippe Mathieu-Daudé                                         const char *name, void *opaque,
13898d7f2e76SPhilippe Mathieu-Daudé                                         Error **errp)
13908d7f2e76SPhilippe Mathieu-Daudé {
13918d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr = MEMORY_REGION(obj);
13928d7f2e76SPhilippe Mathieu-Daudé     char *path = (char *)"";
13938d7f2e76SPhilippe Mathieu-Daudé 
13948d7f2e76SPhilippe Mathieu-Daudé     if (mr->container) {
13958d7f2e76SPhilippe Mathieu-Daudé         path = object_get_canonical_path(OBJECT(mr->container));
13968d7f2e76SPhilippe Mathieu-Daudé     }
13978d7f2e76SPhilippe Mathieu-Daudé     visit_type_str(v, name, &path, errp);
13988d7f2e76SPhilippe Mathieu-Daudé     if (mr->container) {
13998d7f2e76SPhilippe Mathieu-Daudé         g_free(path);
14008d7f2e76SPhilippe Mathieu-Daudé     }
14018d7f2e76SPhilippe Mathieu-Daudé }
14028d7f2e76SPhilippe Mathieu-Daudé 
memory_region_resolve_container(Object * obj,void * opaque,const char * part)14038d7f2e76SPhilippe Mathieu-Daudé static Object *memory_region_resolve_container(Object *obj, void *opaque,
14048d7f2e76SPhilippe Mathieu-Daudé                                                const char *part)
14058d7f2e76SPhilippe Mathieu-Daudé {
14068d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr = MEMORY_REGION(obj);
14078d7f2e76SPhilippe Mathieu-Daudé 
14088d7f2e76SPhilippe Mathieu-Daudé     return OBJECT(mr->container);
14098d7f2e76SPhilippe Mathieu-Daudé }
14108d7f2e76SPhilippe Mathieu-Daudé 
memory_region_get_priority(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)14118d7f2e76SPhilippe Mathieu-Daudé static void memory_region_get_priority(Object *obj, Visitor *v,
14128d7f2e76SPhilippe Mathieu-Daudé                                        const char *name, void *opaque,
14138d7f2e76SPhilippe Mathieu-Daudé                                        Error **errp)
14148d7f2e76SPhilippe Mathieu-Daudé {
14158d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr = MEMORY_REGION(obj);
14168d7f2e76SPhilippe Mathieu-Daudé     int32_t value = mr->priority;
14178d7f2e76SPhilippe Mathieu-Daudé 
14188d7f2e76SPhilippe Mathieu-Daudé     visit_type_int32(v, name, &value, errp);
14198d7f2e76SPhilippe Mathieu-Daudé }
14208d7f2e76SPhilippe Mathieu-Daudé 
memory_region_get_size(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)14218d7f2e76SPhilippe Mathieu-Daudé static void memory_region_get_size(Object *obj, Visitor *v, const char *name,
14228d7f2e76SPhilippe Mathieu-Daudé                                    void *opaque, Error **errp)
14238d7f2e76SPhilippe Mathieu-Daudé {
14248d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr = MEMORY_REGION(obj);
14258d7f2e76SPhilippe Mathieu-Daudé     uint64_t value = memory_region_size(mr);
14268d7f2e76SPhilippe Mathieu-Daudé 
14278d7f2e76SPhilippe Mathieu-Daudé     visit_type_uint64(v, name, &value, errp);
14288d7f2e76SPhilippe Mathieu-Daudé }
14298d7f2e76SPhilippe Mathieu-Daudé 
memory_region_initfn(Object * obj)14308d7f2e76SPhilippe Mathieu-Daudé static void memory_region_initfn(Object *obj)
14318d7f2e76SPhilippe Mathieu-Daudé {
14328d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr = MEMORY_REGION(obj);
14338d7f2e76SPhilippe Mathieu-Daudé     ObjectProperty *op;
14348d7f2e76SPhilippe Mathieu-Daudé 
14358d7f2e76SPhilippe Mathieu-Daudé     mr->ops = &unassigned_mem_ops;
14368d7f2e76SPhilippe Mathieu-Daudé     mr->enabled = true;
14378d7f2e76SPhilippe Mathieu-Daudé     mr->romd_mode = true;
14388d7f2e76SPhilippe Mathieu-Daudé     mr->destructor = memory_region_destructor_none;
14398d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_INIT(&mr->subregions);
14408d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_INIT(&mr->coalesced);
14418d7f2e76SPhilippe Mathieu-Daudé 
14428d7f2e76SPhilippe Mathieu-Daudé     op = object_property_add(OBJECT(mr), "container",
14438d7f2e76SPhilippe Mathieu-Daudé                              "link<" TYPE_MEMORY_REGION ">",
14448d7f2e76SPhilippe Mathieu-Daudé                              memory_region_get_container,
14458d7f2e76SPhilippe Mathieu-Daudé                              NULL, /* memory_region_set_container */
14468d7f2e76SPhilippe Mathieu-Daudé                              NULL, NULL);
14478d7f2e76SPhilippe Mathieu-Daudé     op->resolve = memory_region_resolve_container;
14488d7f2e76SPhilippe Mathieu-Daudé 
14498d7f2e76SPhilippe Mathieu-Daudé     object_property_add_uint64_ptr(OBJECT(mr), "addr",
14508d7f2e76SPhilippe Mathieu-Daudé                                    &mr->addr, OBJ_PROP_FLAG_READ);
14518d7f2e76SPhilippe Mathieu-Daudé     object_property_add(OBJECT(mr), "priority", "uint32",
14528d7f2e76SPhilippe Mathieu-Daudé                         memory_region_get_priority,
14538d7f2e76SPhilippe Mathieu-Daudé                         NULL, /* memory_region_set_priority */
14548d7f2e76SPhilippe Mathieu-Daudé                         NULL, NULL);
14558d7f2e76SPhilippe Mathieu-Daudé     object_property_add(OBJECT(mr), "size", "uint64",
14568d7f2e76SPhilippe Mathieu-Daudé                         memory_region_get_size,
14578d7f2e76SPhilippe Mathieu-Daudé                         NULL, /* memory_region_set_size, */
14588d7f2e76SPhilippe Mathieu-Daudé                         NULL, NULL);
14598d7f2e76SPhilippe Mathieu-Daudé }
14608d7f2e76SPhilippe Mathieu-Daudé 
iommu_memory_region_initfn(Object * obj)14618d7f2e76SPhilippe Mathieu-Daudé static void iommu_memory_region_initfn(Object *obj)
14628d7f2e76SPhilippe Mathieu-Daudé {
14638d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr = MEMORY_REGION(obj);
14648d7f2e76SPhilippe Mathieu-Daudé 
14658d7f2e76SPhilippe Mathieu-Daudé     mr->is_iommu = true;
14668d7f2e76SPhilippe Mathieu-Daudé }
14678d7f2e76SPhilippe Mathieu-Daudé 
unassigned_mem_read(void * opaque,hwaddr addr,unsigned size)14688d7f2e76SPhilippe Mathieu-Daudé static uint64_t unassigned_mem_read(void *opaque, hwaddr addr,
14698d7f2e76SPhilippe Mathieu-Daudé                                     unsigned size)
14708d7f2e76SPhilippe Mathieu-Daudé {
14718d7f2e76SPhilippe Mathieu-Daudé #ifdef DEBUG_UNASSIGNED
14728d7f2e76SPhilippe Mathieu-Daudé     printf("Unassigned mem read " HWADDR_FMT_plx "\n", addr);
14738d7f2e76SPhilippe Mathieu-Daudé #endif
14748d7f2e76SPhilippe Mathieu-Daudé     return 0;
14758d7f2e76SPhilippe Mathieu-Daudé }
14768d7f2e76SPhilippe Mathieu-Daudé 
unassigned_mem_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)14778d7f2e76SPhilippe Mathieu-Daudé static void unassigned_mem_write(void *opaque, hwaddr addr,
14788d7f2e76SPhilippe Mathieu-Daudé                                  uint64_t val, unsigned size)
14798d7f2e76SPhilippe Mathieu-Daudé {
14808d7f2e76SPhilippe Mathieu-Daudé #ifdef DEBUG_UNASSIGNED
14818d7f2e76SPhilippe Mathieu-Daudé     printf("Unassigned mem write " HWADDR_FMT_plx " = 0x%"PRIx64"\n", addr, val);
14828d7f2e76SPhilippe Mathieu-Daudé #endif
14838d7f2e76SPhilippe Mathieu-Daudé }
14848d7f2e76SPhilippe Mathieu-Daudé 
unassigned_mem_accepts(void * opaque,hwaddr addr,unsigned size,bool is_write,MemTxAttrs attrs)14858d7f2e76SPhilippe Mathieu-Daudé static bool unassigned_mem_accepts(void *opaque, hwaddr addr,
14868d7f2e76SPhilippe Mathieu-Daudé                                    unsigned size, bool is_write,
14878d7f2e76SPhilippe Mathieu-Daudé                                    MemTxAttrs attrs)
14888d7f2e76SPhilippe Mathieu-Daudé {
14898d7f2e76SPhilippe Mathieu-Daudé     return false;
14908d7f2e76SPhilippe Mathieu-Daudé }
14918d7f2e76SPhilippe Mathieu-Daudé 
14928d7f2e76SPhilippe Mathieu-Daudé const MemoryRegionOps unassigned_mem_ops = {
14938d7f2e76SPhilippe Mathieu-Daudé     .valid.accepts = unassigned_mem_accepts,
14948d7f2e76SPhilippe Mathieu-Daudé     .endianness = DEVICE_NATIVE_ENDIAN,
14958d7f2e76SPhilippe Mathieu-Daudé };
14968d7f2e76SPhilippe Mathieu-Daudé 
memory_region_ram_device_read(void * opaque,hwaddr addr,unsigned size)14978d7f2e76SPhilippe Mathieu-Daudé static uint64_t memory_region_ram_device_read(void *opaque,
14988d7f2e76SPhilippe Mathieu-Daudé                                               hwaddr addr, unsigned size)
14998d7f2e76SPhilippe Mathieu-Daudé {
15008d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr = opaque;
15012b8fe81bSPatrick Venture     uint64_t data = ldn_he_p(mr->ram_block->host + addr, size);
15028d7f2e76SPhilippe Mathieu-Daudé 
15038d7f2e76SPhilippe Mathieu-Daudé     trace_memory_region_ram_device_read(get_cpu_index(), mr, addr, data, size);
15048d7f2e76SPhilippe Mathieu-Daudé 
15058d7f2e76SPhilippe Mathieu-Daudé     return data;
15068d7f2e76SPhilippe Mathieu-Daudé }
15078d7f2e76SPhilippe Mathieu-Daudé 
memory_region_ram_device_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)15088d7f2e76SPhilippe Mathieu-Daudé static void memory_region_ram_device_write(void *opaque, hwaddr addr,
15098d7f2e76SPhilippe Mathieu-Daudé                                            uint64_t data, unsigned size)
15108d7f2e76SPhilippe Mathieu-Daudé {
15118d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr = opaque;
15128d7f2e76SPhilippe Mathieu-Daudé 
15138d7f2e76SPhilippe Mathieu-Daudé     trace_memory_region_ram_device_write(get_cpu_index(), mr, addr, data, size);
15148d7f2e76SPhilippe Mathieu-Daudé 
15152b8fe81bSPatrick Venture     stn_he_p(mr->ram_block->host + addr, size, data);
15168d7f2e76SPhilippe Mathieu-Daudé }
15178d7f2e76SPhilippe Mathieu-Daudé 
15188d7f2e76SPhilippe Mathieu-Daudé static const MemoryRegionOps ram_device_mem_ops = {
15198d7f2e76SPhilippe Mathieu-Daudé     .read = memory_region_ram_device_read,
15208d7f2e76SPhilippe Mathieu-Daudé     .write = memory_region_ram_device_write,
15218d7f2e76SPhilippe Mathieu-Daudé     .endianness = DEVICE_HOST_ENDIAN,
15228d7f2e76SPhilippe Mathieu-Daudé     .valid = {
15238d7f2e76SPhilippe Mathieu-Daudé         .min_access_size = 1,
15248d7f2e76SPhilippe Mathieu-Daudé         .max_access_size = 8,
15258d7f2e76SPhilippe Mathieu-Daudé         .unaligned = true,
15268d7f2e76SPhilippe Mathieu-Daudé     },
15278d7f2e76SPhilippe Mathieu-Daudé     .impl = {
15288d7f2e76SPhilippe Mathieu-Daudé         .min_access_size = 1,
15298d7f2e76SPhilippe Mathieu-Daudé         .max_access_size = 8,
15308d7f2e76SPhilippe Mathieu-Daudé         .unaligned = true,
15318d7f2e76SPhilippe Mathieu-Daudé     },
15328d7f2e76SPhilippe Mathieu-Daudé };
15338d7f2e76SPhilippe Mathieu-Daudé 
memory_region_access_valid(MemoryRegion * mr,hwaddr addr,unsigned size,bool is_write,MemTxAttrs attrs)15348d7f2e76SPhilippe Mathieu-Daudé bool memory_region_access_valid(MemoryRegion *mr,
15358d7f2e76SPhilippe Mathieu-Daudé                                 hwaddr addr,
15368d7f2e76SPhilippe Mathieu-Daudé                                 unsigned size,
15378d7f2e76SPhilippe Mathieu-Daudé                                 bool is_write,
15388d7f2e76SPhilippe Mathieu-Daudé                                 MemTxAttrs attrs)
15398d7f2e76SPhilippe Mathieu-Daudé {
15408d7f2e76SPhilippe Mathieu-Daudé     if (mr->ops->valid.accepts
15418d7f2e76SPhilippe Mathieu-Daudé         && !mr->ops->valid.accepts(mr->opaque, addr, size, is_write, attrs)) {
15428d7f2e76SPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR, "Invalid %s at addr 0x%" HWADDR_PRIX
15438d7f2e76SPhilippe Mathieu-Daudé                       ", size %u, region '%s', reason: rejected\n",
15448d7f2e76SPhilippe Mathieu-Daudé                       is_write ? "write" : "read",
15458d7f2e76SPhilippe Mathieu-Daudé                       addr, size, memory_region_name(mr));
15468d7f2e76SPhilippe Mathieu-Daudé         return false;
15478d7f2e76SPhilippe Mathieu-Daudé     }
15488d7f2e76SPhilippe Mathieu-Daudé 
15498d7f2e76SPhilippe Mathieu-Daudé     if (!mr->ops->valid.unaligned && (addr & (size - 1))) {
15508d7f2e76SPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR, "Invalid %s at addr 0x%" HWADDR_PRIX
15518d7f2e76SPhilippe Mathieu-Daudé                       ", size %u, region '%s', reason: unaligned\n",
15528d7f2e76SPhilippe Mathieu-Daudé                       is_write ? "write" : "read",
15538d7f2e76SPhilippe Mathieu-Daudé                       addr, size, memory_region_name(mr));
15548d7f2e76SPhilippe Mathieu-Daudé         return false;
15558d7f2e76SPhilippe Mathieu-Daudé     }
15568d7f2e76SPhilippe Mathieu-Daudé 
15578d7f2e76SPhilippe Mathieu-Daudé     /* Treat zero as compatibility all valid */
15588d7f2e76SPhilippe Mathieu-Daudé     if (!mr->ops->valid.max_access_size) {
15598d7f2e76SPhilippe Mathieu-Daudé         return true;
15608d7f2e76SPhilippe Mathieu-Daudé     }
15618d7f2e76SPhilippe Mathieu-Daudé 
15628d7f2e76SPhilippe Mathieu-Daudé     if (size > mr->ops->valid.max_access_size
15638d7f2e76SPhilippe Mathieu-Daudé         || size < mr->ops->valid.min_access_size) {
15648d7f2e76SPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR, "Invalid %s at addr 0x%" HWADDR_PRIX
15658d7f2e76SPhilippe Mathieu-Daudé                       ", size %u, region '%s', reason: invalid size "
15668d7f2e76SPhilippe Mathieu-Daudé                       "(min:%u max:%u)\n",
15678d7f2e76SPhilippe Mathieu-Daudé                       is_write ? "write" : "read",
15688d7f2e76SPhilippe Mathieu-Daudé                       addr, size, memory_region_name(mr),
15698d7f2e76SPhilippe Mathieu-Daudé                       mr->ops->valid.min_access_size,
15708d7f2e76SPhilippe Mathieu-Daudé                       mr->ops->valid.max_access_size);
15718d7f2e76SPhilippe Mathieu-Daudé         return false;
15728d7f2e76SPhilippe Mathieu-Daudé     }
15738d7f2e76SPhilippe Mathieu-Daudé     return true;
15748d7f2e76SPhilippe Mathieu-Daudé }
15758d7f2e76SPhilippe Mathieu-Daudé 
memory_region_dispatch_read1(MemoryRegion * mr,hwaddr addr,uint64_t * pval,unsigned size,MemTxAttrs attrs)15768d7f2e76SPhilippe Mathieu-Daudé static MemTxResult memory_region_dispatch_read1(MemoryRegion *mr,
15778d7f2e76SPhilippe Mathieu-Daudé                                                 hwaddr addr,
15788d7f2e76SPhilippe Mathieu-Daudé                                                 uint64_t *pval,
15798d7f2e76SPhilippe Mathieu-Daudé                                                 unsigned size,
15808d7f2e76SPhilippe Mathieu-Daudé                                                 MemTxAttrs attrs)
15818d7f2e76SPhilippe Mathieu-Daudé {
15828d7f2e76SPhilippe Mathieu-Daudé     *pval = 0;
15838d7f2e76SPhilippe Mathieu-Daudé 
15848d7f2e76SPhilippe Mathieu-Daudé     if (mr->ops->read) {
15858d7f2e76SPhilippe Mathieu-Daudé         return access_with_adjusted_size(addr, pval, size,
15868d7f2e76SPhilippe Mathieu-Daudé                                          mr->ops->impl.min_access_size,
15878d7f2e76SPhilippe Mathieu-Daudé                                          mr->ops->impl.max_access_size,
1588*557e1d67SAndrew Jeffery                                          mr->ops->impl.unaligned,
15898d7f2e76SPhilippe Mathieu-Daudé                                          memory_region_read_accessor,
15908d7f2e76SPhilippe Mathieu-Daudé                                          mr, attrs);
15918d7f2e76SPhilippe Mathieu-Daudé     } else {
15928d7f2e76SPhilippe Mathieu-Daudé         return access_with_adjusted_size(addr, pval, size,
15938d7f2e76SPhilippe Mathieu-Daudé                                          mr->ops->impl.min_access_size,
15948d7f2e76SPhilippe Mathieu-Daudé                                          mr->ops->impl.max_access_size,
1595*557e1d67SAndrew Jeffery                                          mr->ops->impl.unaligned,
15968d7f2e76SPhilippe Mathieu-Daudé                                          memory_region_read_with_attrs_accessor,
15978d7f2e76SPhilippe Mathieu-Daudé                                          mr, attrs);
15988d7f2e76SPhilippe Mathieu-Daudé     }
15998d7f2e76SPhilippe Mathieu-Daudé }
16008d7f2e76SPhilippe Mathieu-Daudé 
memory_region_dispatch_read(MemoryRegion * mr,hwaddr addr,uint64_t * pval,MemOp op,MemTxAttrs attrs)16018d7f2e76SPhilippe Mathieu-Daudé MemTxResult memory_region_dispatch_read(MemoryRegion *mr,
16028d7f2e76SPhilippe Mathieu-Daudé                                         hwaddr addr,
16038d7f2e76SPhilippe Mathieu-Daudé                                         uint64_t *pval,
16048d7f2e76SPhilippe Mathieu-Daudé                                         MemOp op,
16058d7f2e76SPhilippe Mathieu-Daudé                                         MemTxAttrs attrs)
16068d7f2e76SPhilippe Mathieu-Daudé {
16078d7f2e76SPhilippe Mathieu-Daudé     unsigned size = memop_size(op);
16088d7f2e76SPhilippe Mathieu-Daudé     MemTxResult r;
16098d7f2e76SPhilippe Mathieu-Daudé 
16108d7f2e76SPhilippe Mathieu-Daudé     if (mr->alias) {
16118d7f2e76SPhilippe Mathieu-Daudé         return memory_region_dispatch_read(mr->alias,
16128d7f2e76SPhilippe Mathieu-Daudé                                            mr->alias_offset + addr,
16138d7f2e76SPhilippe Mathieu-Daudé                                            pval, op, attrs);
16148d7f2e76SPhilippe Mathieu-Daudé     }
16158d7f2e76SPhilippe Mathieu-Daudé     if (!memory_region_access_valid(mr, addr, size, false, attrs)) {
16168d7f2e76SPhilippe Mathieu-Daudé         *pval = unassigned_mem_read(mr, addr, size);
16178d7f2e76SPhilippe Mathieu-Daudé         return MEMTX_DECODE_ERROR;
16188d7f2e76SPhilippe Mathieu-Daudé     }
16198d7f2e76SPhilippe Mathieu-Daudé 
16208d7f2e76SPhilippe Mathieu-Daudé     r = memory_region_dispatch_read1(mr, addr, pval, size, attrs);
16218d7f2e76SPhilippe Mathieu-Daudé     adjust_endianness(mr, pval, op);
16228d7f2e76SPhilippe Mathieu-Daudé     return r;
16238d7f2e76SPhilippe Mathieu-Daudé }
16248d7f2e76SPhilippe Mathieu-Daudé 
16258d7f2e76SPhilippe Mathieu-Daudé /* Return true if an eventfd was signalled */
memory_region_dispatch_write_eventfds(MemoryRegion * mr,hwaddr addr,uint64_t data,unsigned size,MemTxAttrs attrs)16268d7f2e76SPhilippe Mathieu-Daudé static bool memory_region_dispatch_write_eventfds(MemoryRegion *mr,
16278d7f2e76SPhilippe Mathieu-Daudé                                                     hwaddr addr,
16288d7f2e76SPhilippe Mathieu-Daudé                                                     uint64_t data,
16298d7f2e76SPhilippe Mathieu-Daudé                                                     unsigned size,
16308d7f2e76SPhilippe Mathieu-Daudé                                                     MemTxAttrs attrs)
16318d7f2e76SPhilippe Mathieu-Daudé {
16328d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionIoeventfd ioeventfd = {
16338d7f2e76SPhilippe Mathieu-Daudé         .addr = addrrange_make(int128_make64(addr), int128_make64(size)),
16348d7f2e76SPhilippe Mathieu-Daudé         .data = data,
16358d7f2e76SPhilippe Mathieu-Daudé     };
16368d7f2e76SPhilippe Mathieu-Daudé     unsigned i;
16378d7f2e76SPhilippe Mathieu-Daudé 
16388d7f2e76SPhilippe Mathieu-Daudé     for (i = 0; i < mr->ioeventfd_nb; i++) {
16398d7f2e76SPhilippe Mathieu-Daudé         ioeventfd.match_data = mr->ioeventfds[i].match_data;
16408d7f2e76SPhilippe Mathieu-Daudé         ioeventfd.e = mr->ioeventfds[i].e;
16418d7f2e76SPhilippe Mathieu-Daudé 
16428d7f2e76SPhilippe Mathieu-Daudé         if (memory_region_ioeventfd_equal(&ioeventfd, &mr->ioeventfds[i])) {
16438d7f2e76SPhilippe Mathieu-Daudé             event_notifier_set(ioeventfd.e);
16448d7f2e76SPhilippe Mathieu-Daudé             return true;
16458d7f2e76SPhilippe Mathieu-Daudé         }
16468d7f2e76SPhilippe Mathieu-Daudé     }
16478d7f2e76SPhilippe Mathieu-Daudé 
16488d7f2e76SPhilippe Mathieu-Daudé     return false;
16498d7f2e76SPhilippe Mathieu-Daudé }
16508d7f2e76SPhilippe Mathieu-Daudé 
memory_region_dispatch_write(MemoryRegion * mr,hwaddr addr,uint64_t data,MemOp op,MemTxAttrs attrs)16518d7f2e76SPhilippe Mathieu-Daudé MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
16528d7f2e76SPhilippe Mathieu-Daudé                                          hwaddr addr,
16538d7f2e76SPhilippe Mathieu-Daudé                                          uint64_t data,
16548d7f2e76SPhilippe Mathieu-Daudé                                          MemOp op,
16558d7f2e76SPhilippe Mathieu-Daudé                                          MemTxAttrs attrs)
16568d7f2e76SPhilippe Mathieu-Daudé {
16578d7f2e76SPhilippe Mathieu-Daudé     unsigned size = memop_size(op);
16588d7f2e76SPhilippe Mathieu-Daudé 
16598d7f2e76SPhilippe Mathieu-Daudé     if (mr->alias) {
16608d7f2e76SPhilippe Mathieu-Daudé         return memory_region_dispatch_write(mr->alias,
16618d7f2e76SPhilippe Mathieu-Daudé                                             mr->alias_offset + addr,
16628d7f2e76SPhilippe Mathieu-Daudé                                             data, op, attrs);
16638d7f2e76SPhilippe Mathieu-Daudé     }
16648d7f2e76SPhilippe Mathieu-Daudé     if (!memory_region_access_valid(mr, addr, size, true, attrs)) {
16658d7f2e76SPhilippe Mathieu-Daudé         unassigned_mem_write(mr, addr, data, size);
16668d7f2e76SPhilippe Mathieu-Daudé         return MEMTX_DECODE_ERROR;
16678d7f2e76SPhilippe Mathieu-Daudé     }
16688d7f2e76SPhilippe Mathieu-Daudé 
16698d7f2e76SPhilippe Mathieu-Daudé     adjust_endianness(mr, &data, op);
16708d7f2e76SPhilippe Mathieu-Daudé 
1671126e7f78SPaolo Bonzini     /*
1672126e7f78SPaolo Bonzini      * FIXME: it's not clear why under KVM the write would be processed
1673126e7f78SPaolo Bonzini      * directly, instead of going through eventfd.  This probably should
1674126e7f78SPaolo Bonzini      * test "tcg_enabled() || qtest_enabled()", or should just go away.
1675126e7f78SPaolo Bonzini      */
1676126e7f78SPaolo Bonzini     if (!kvm_enabled() &&
16778d7f2e76SPhilippe Mathieu-Daudé         memory_region_dispatch_write_eventfds(mr, addr, data, size, attrs)) {
16788d7f2e76SPhilippe Mathieu-Daudé         return MEMTX_OK;
16798d7f2e76SPhilippe Mathieu-Daudé     }
16808d7f2e76SPhilippe Mathieu-Daudé 
16818d7f2e76SPhilippe Mathieu-Daudé     if (mr->ops->write) {
1682*557e1d67SAndrew Jeffery         return access_with_adjusted_size_aligned(addr, &data, size,
16838d7f2e76SPhilippe Mathieu-Daudé                                          mr->ops->impl.min_access_size,
16848d7f2e76SPhilippe Mathieu-Daudé                                          mr->ops->impl.max_access_size,
16858d7f2e76SPhilippe Mathieu-Daudé                                          memory_region_write_accessor, mr,
16868d7f2e76SPhilippe Mathieu-Daudé                                          attrs);
16878d7f2e76SPhilippe Mathieu-Daudé     } else {
16888d7f2e76SPhilippe Mathieu-Daudé         return
1689*557e1d67SAndrew Jeffery             access_with_adjusted_size_aligned(addr, &data, size,
16908d7f2e76SPhilippe Mathieu-Daudé                                       mr->ops->impl.min_access_size,
16918d7f2e76SPhilippe Mathieu-Daudé                                       mr->ops->impl.max_access_size,
16928d7f2e76SPhilippe Mathieu-Daudé                                       memory_region_write_with_attrs_accessor,
16938d7f2e76SPhilippe Mathieu-Daudé                                       mr, attrs);
16948d7f2e76SPhilippe Mathieu-Daudé     }
16958d7f2e76SPhilippe Mathieu-Daudé }
16968d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_io(MemoryRegion * mr,Object * owner,const MemoryRegionOps * ops,void * opaque,const char * name,uint64_t size)16978d7f2e76SPhilippe Mathieu-Daudé void memory_region_init_io(MemoryRegion *mr,
16988d7f2e76SPhilippe Mathieu-Daudé                            Object *owner,
16998d7f2e76SPhilippe Mathieu-Daudé                            const MemoryRegionOps *ops,
17008d7f2e76SPhilippe Mathieu-Daudé                            void *opaque,
17018d7f2e76SPhilippe Mathieu-Daudé                            const char *name,
17028d7f2e76SPhilippe Mathieu-Daudé                            uint64_t size)
17038d7f2e76SPhilippe Mathieu-Daudé {
17048d7f2e76SPhilippe Mathieu-Daudé     memory_region_init(mr, owner, name, size);
17058d7f2e76SPhilippe Mathieu-Daudé     mr->ops = ops ? ops : &unassigned_mem_ops;
17068d7f2e76SPhilippe Mathieu-Daudé     mr->opaque = opaque;
17078d7f2e76SPhilippe Mathieu-Daudé     mr->terminates = true;
17088d7f2e76SPhilippe Mathieu-Daudé }
17098d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_ram_nomigrate(MemoryRegion * mr,Object * owner,const char * name,uint64_t size,Error ** errp)171062c19b72SPhilippe Mathieu-Daudé bool memory_region_init_ram_nomigrate(MemoryRegion *mr,
17118d7f2e76SPhilippe Mathieu-Daudé                                       Object *owner,
17128d7f2e76SPhilippe Mathieu-Daudé                                       const char *name,
17138d7f2e76SPhilippe Mathieu-Daudé                                       uint64_t size,
17148d7f2e76SPhilippe Mathieu-Daudé                                       Error **errp)
17158d7f2e76SPhilippe Mathieu-Daudé {
171662c19b72SPhilippe Mathieu-Daudé     return memory_region_init_ram_flags_nomigrate(mr, owner, name,
171762c19b72SPhilippe Mathieu-Daudé                                                   size, 0, errp);
17188d7f2e76SPhilippe Mathieu-Daudé }
17198d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_ram_flags_nomigrate(MemoryRegion * mr,Object * owner,const char * name,uint64_t size,uint32_t ram_flags,Error ** errp)1720cbbc4340SPhilippe Mathieu-Daudé bool memory_region_init_ram_flags_nomigrate(MemoryRegion *mr,
17218d7f2e76SPhilippe Mathieu-Daudé                                             Object *owner,
17228d7f2e76SPhilippe Mathieu-Daudé                                             const char *name,
17238d7f2e76SPhilippe Mathieu-Daudé                                             uint64_t size,
17248d7f2e76SPhilippe Mathieu-Daudé                                             uint32_t ram_flags,
17258d7f2e76SPhilippe Mathieu-Daudé                                             Error **errp)
17268d7f2e76SPhilippe Mathieu-Daudé {
17278d7f2e76SPhilippe Mathieu-Daudé     Error *err = NULL;
17288d7f2e76SPhilippe Mathieu-Daudé     memory_region_init(mr, owner, name, size);
17298d7f2e76SPhilippe Mathieu-Daudé     mr->ram = true;
17308d7f2e76SPhilippe Mathieu-Daudé     mr->terminates = true;
17318d7f2e76SPhilippe Mathieu-Daudé     mr->destructor = memory_region_destructor_ram;
17328d7f2e76SPhilippe Mathieu-Daudé     mr->ram_block = qemu_ram_alloc(size, ram_flags, mr, &err);
17338d7f2e76SPhilippe Mathieu-Daudé     if (err) {
17348d7f2e76SPhilippe Mathieu-Daudé         mr->size = int128_zero();
17358d7f2e76SPhilippe Mathieu-Daudé         object_unparent(OBJECT(mr));
17368d7f2e76SPhilippe Mathieu-Daudé         error_propagate(errp, err);
1737cbbc4340SPhilippe Mathieu-Daudé         return false;
17388d7f2e76SPhilippe Mathieu-Daudé     }
1739cbbc4340SPhilippe Mathieu-Daudé     return true;
17408d7f2e76SPhilippe Mathieu-Daudé }
17418d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_resizeable_ram(MemoryRegion * mr,Object * owner,const char * name,uint64_t size,uint64_t max_size,void (* resized)(const char *,uint64_t length,void * host),Error ** errp)1742f25a9fbbSPhilippe Mathieu-Daudé bool memory_region_init_resizeable_ram(MemoryRegion *mr,
17438d7f2e76SPhilippe Mathieu-Daudé                                        Object *owner,
17448d7f2e76SPhilippe Mathieu-Daudé                                        const char *name,
17458d7f2e76SPhilippe Mathieu-Daudé                                        uint64_t size,
17468d7f2e76SPhilippe Mathieu-Daudé                                        uint64_t max_size,
17478d7f2e76SPhilippe Mathieu-Daudé                                        void (*resized)(const char*,
17488d7f2e76SPhilippe Mathieu-Daudé                                                        uint64_t length,
17498d7f2e76SPhilippe Mathieu-Daudé                                                        void *host),
17508d7f2e76SPhilippe Mathieu-Daudé                                        Error **errp)
17518d7f2e76SPhilippe Mathieu-Daudé {
17528d7f2e76SPhilippe Mathieu-Daudé     Error *err = NULL;
17538d7f2e76SPhilippe Mathieu-Daudé     memory_region_init(mr, owner, name, size);
17548d7f2e76SPhilippe Mathieu-Daudé     mr->ram = true;
17558d7f2e76SPhilippe Mathieu-Daudé     mr->terminates = true;
17568d7f2e76SPhilippe Mathieu-Daudé     mr->destructor = memory_region_destructor_ram;
17578d7f2e76SPhilippe Mathieu-Daudé     mr->ram_block = qemu_ram_alloc_resizeable(size, max_size, resized,
17588d7f2e76SPhilippe Mathieu-Daudé                                               mr, &err);
17598d7f2e76SPhilippe Mathieu-Daudé     if (err) {
17608d7f2e76SPhilippe Mathieu-Daudé         mr->size = int128_zero();
17618d7f2e76SPhilippe Mathieu-Daudé         object_unparent(OBJECT(mr));
17628d7f2e76SPhilippe Mathieu-Daudé         error_propagate(errp, err);
1763f25a9fbbSPhilippe Mathieu-Daudé         return false;
17648d7f2e76SPhilippe Mathieu-Daudé     }
1765f25a9fbbSPhilippe Mathieu-Daudé     return true;
17668d7f2e76SPhilippe Mathieu-Daudé }
17678d7f2e76SPhilippe Mathieu-Daudé 
17688d7f2e76SPhilippe Mathieu-Daudé #ifdef CONFIG_POSIX
memory_region_init_ram_from_file(MemoryRegion * mr,Object * owner,const char * name,uint64_t size,uint64_t align,uint32_t ram_flags,const char * path,ram_addr_t offset,Error ** errp)17699b9d11acSPhilippe Mathieu-Daudé bool memory_region_init_ram_from_file(MemoryRegion *mr,
17708d7f2e76SPhilippe Mathieu-Daudé                                       Object *owner,
17718d7f2e76SPhilippe Mathieu-Daudé                                       const char *name,
17728d7f2e76SPhilippe Mathieu-Daudé                                       uint64_t size,
17738d7f2e76SPhilippe Mathieu-Daudé                                       uint64_t align,
17748d7f2e76SPhilippe Mathieu-Daudé                                       uint32_t ram_flags,
17758d7f2e76SPhilippe Mathieu-Daudé                                       const char *path,
17768d7f2e76SPhilippe Mathieu-Daudé                                       ram_addr_t offset,
17778d7f2e76SPhilippe Mathieu-Daudé                                       Error **errp)
17788d7f2e76SPhilippe Mathieu-Daudé {
17798d7f2e76SPhilippe Mathieu-Daudé     Error *err = NULL;
17808d7f2e76SPhilippe Mathieu-Daudé     memory_region_init(mr, owner, name, size);
17818d7f2e76SPhilippe Mathieu-Daudé     mr->ram = true;
17828d7f2e76SPhilippe Mathieu-Daudé     mr->readonly = !!(ram_flags & RAM_READONLY);
17838d7f2e76SPhilippe Mathieu-Daudé     mr->terminates = true;
17848d7f2e76SPhilippe Mathieu-Daudé     mr->destructor = memory_region_destructor_ram;
17858d7f2e76SPhilippe Mathieu-Daudé     mr->align = align;
17868d7f2e76SPhilippe Mathieu-Daudé     mr->ram_block = qemu_ram_alloc_from_file(size, mr, ram_flags, path,
17878d7f2e76SPhilippe Mathieu-Daudé                                              offset, &err);
17888d7f2e76SPhilippe Mathieu-Daudé     if (err) {
17898d7f2e76SPhilippe Mathieu-Daudé         mr->size = int128_zero();
17908d7f2e76SPhilippe Mathieu-Daudé         object_unparent(OBJECT(mr));
17918d7f2e76SPhilippe Mathieu-Daudé         error_propagate(errp, err);
17929b9d11acSPhilippe Mathieu-Daudé         return false;
17938d7f2e76SPhilippe Mathieu-Daudé     }
17949b9d11acSPhilippe Mathieu-Daudé     return true;
17958d7f2e76SPhilippe Mathieu-Daudé }
17968d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_ram_from_fd(MemoryRegion * mr,Object * owner,const char * name,uint64_t size,uint32_t ram_flags,int fd,ram_addr_t offset,Error ** errp)17979583a905SPhilippe Mathieu-Daudé bool memory_region_init_ram_from_fd(MemoryRegion *mr,
17988d7f2e76SPhilippe Mathieu-Daudé                                     Object *owner,
17998d7f2e76SPhilippe Mathieu-Daudé                                     const char *name,
18008d7f2e76SPhilippe Mathieu-Daudé                                     uint64_t size,
18018d7f2e76SPhilippe Mathieu-Daudé                                     uint32_t ram_flags,
18028d7f2e76SPhilippe Mathieu-Daudé                                     int fd,
18038d7f2e76SPhilippe Mathieu-Daudé                                     ram_addr_t offset,
18048d7f2e76SPhilippe Mathieu-Daudé                                     Error **errp)
18058d7f2e76SPhilippe Mathieu-Daudé {
18068d7f2e76SPhilippe Mathieu-Daudé     Error *err = NULL;
18078d7f2e76SPhilippe Mathieu-Daudé     memory_region_init(mr, owner, name, size);
18088d7f2e76SPhilippe Mathieu-Daudé     mr->ram = true;
18098d7f2e76SPhilippe Mathieu-Daudé     mr->readonly = !!(ram_flags & RAM_READONLY);
18108d7f2e76SPhilippe Mathieu-Daudé     mr->terminates = true;
18118d7f2e76SPhilippe Mathieu-Daudé     mr->destructor = memory_region_destructor_ram;
18128d7f2e76SPhilippe Mathieu-Daudé     mr->ram_block = qemu_ram_alloc_from_fd(size, mr, ram_flags, fd, offset,
18138d7f2e76SPhilippe Mathieu-Daudé                                            &err);
18148d7f2e76SPhilippe Mathieu-Daudé     if (err) {
18158d7f2e76SPhilippe Mathieu-Daudé         mr->size = int128_zero();
18168d7f2e76SPhilippe Mathieu-Daudé         object_unparent(OBJECT(mr));
18178d7f2e76SPhilippe Mathieu-Daudé         error_propagate(errp, err);
18189583a905SPhilippe Mathieu-Daudé         return false;
18198d7f2e76SPhilippe Mathieu-Daudé     }
18209583a905SPhilippe Mathieu-Daudé     return true;
18218d7f2e76SPhilippe Mathieu-Daudé }
18228d7f2e76SPhilippe Mathieu-Daudé #endif
18238d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_ram_ptr(MemoryRegion * mr,Object * owner,const char * name,uint64_t size,void * ptr)18248d7f2e76SPhilippe Mathieu-Daudé void memory_region_init_ram_ptr(MemoryRegion *mr,
18258d7f2e76SPhilippe Mathieu-Daudé                                 Object *owner,
18268d7f2e76SPhilippe Mathieu-Daudé                                 const char *name,
18278d7f2e76SPhilippe Mathieu-Daudé                                 uint64_t size,
18288d7f2e76SPhilippe Mathieu-Daudé                                 void *ptr)
18298d7f2e76SPhilippe Mathieu-Daudé {
18308d7f2e76SPhilippe Mathieu-Daudé     memory_region_init(mr, owner, name, size);
18318d7f2e76SPhilippe Mathieu-Daudé     mr->ram = true;
18328d7f2e76SPhilippe Mathieu-Daudé     mr->terminates = true;
18338d7f2e76SPhilippe Mathieu-Daudé     mr->destructor = memory_region_destructor_ram;
18348d7f2e76SPhilippe Mathieu-Daudé 
18358d7f2e76SPhilippe Mathieu-Daudé     /* qemu_ram_alloc_from_ptr cannot fail with ptr != NULL.  */
18368d7f2e76SPhilippe Mathieu-Daudé     assert(ptr != NULL);
1837cd911363SPhilippe Mathieu-Daudé     mr->ram_block = qemu_ram_alloc_from_ptr(size, ptr, mr, &error_abort);
18388d7f2e76SPhilippe Mathieu-Daudé }
18398d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_ram_device_ptr(MemoryRegion * mr,Object * owner,const char * name,uint64_t size,void * ptr)18408d7f2e76SPhilippe Mathieu-Daudé void memory_region_init_ram_device_ptr(MemoryRegion *mr,
18418d7f2e76SPhilippe Mathieu-Daudé                                        Object *owner,
18428d7f2e76SPhilippe Mathieu-Daudé                                        const char *name,
18438d7f2e76SPhilippe Mathieu-Daudé                                        uint64_t size,
18448d7f2e76SPhilippe Mathieu-Daudé                                        void *ptr)
18458d7f2e76SPhilippe Mathieu-Daudé {
18468d7f2e76SPhilippe Mathieu-Daudé     memory_region_init(mr, owner, name, size);
18478d7f2e76SPhilippe Mathieu-Daudé     mr->ram = true;
18488d7f2e76SPhilippe Mathieu-Daudé     mr->terminates = true;
18498d7f2e76SPhilippe Mathieu-Daudé     mr->ram_device = true;
18508d7f2e76SPhilippe Mathieu-Daudé     mr->ops = &ram_device_mem_ops;
18518d7f2e76SPhilippe Mathieu-Daudé     mr->opaque = mr;
18528d7f2e76SPhilippe Mathieu-Daudé     mr->destructor = memory_region_destructor_ram;
18538d7f2e76SPhilippe Mathieu-Daudé 
18548d7f2e76SPhilippe Mathieu-Daudé     /* qemu_ram_alloc_from_ptr cannot fail with ptr != NULL.  */
18558d7f2e76SPhilippe Mathieu-Daudé     assert(ptr != NULL);
1856cd911363SPhilippe Mathieu-Daudé     mr->ram_block = qemu_ram_alloc_from_ptr(size, ptr, mr, &error_abort);
18578d7f2e76SPhilippe Mathieu-Daudé }
18588d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_alias(MemoryRegion * mr,Object * owner,const char * name,MemoryRegion * orig,hwaddr offset,uint64_t size)18598d7f2e76SPhilippe Mathieu-Daudé void memory_region_init_alias(MemoryRegion *mr,
18608d7f2e76SPhilippe Mathieu-Daudé                               Object *owner,
18618d7f2e76SPhilippe Mathieu-Daudé                               const char *name,
18628d7f2e76SPhilippe Mathieu-Daudé                               MemoryRegion *orig,
18638d7f2e76SPhilippe Mathieu-Daudé                               hwaddr offset,
18648d7f2e76SPhilippe Mathieu-Daudé                               uint64_t size)
18658d7f2e76SPhilippe Mathieu-Daudé {
18668d7f2e76SPhilippe Mathieu-Daudé     memory_region_init(mr, owner, name, size);
18678d7f2e76SPhilippe Mathieu-Daudé     mr->alias = orig;
18688d7f2e76SPhilippe Mathieu-Daudé     mr->alias_offset = offset;
18698d7f2e76SPhilippe Mathieu-Daudé }
18708d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_rom_nomigrate(MemoryRegion * mr,Object * owner,const char * name,uint64_t size,Error ** errp)1871197faa70SPhilippe Mathieu-Daudé bool memory_region_init_rom_nomigrate(MemoryRegion *mr,
18728d7f2e76SPhilippe Mathieu-Daudé                                       Object *owner,
18738d7f2e76SPhilippe Mathieu-Daudé                                       const char *name,
18748d7f2e76SPhilippe Mathieu-Daudé                                       uint64_t size,
18758d7f2e76SPhilippe Mathieu-Daudé                                       Error **errp)
18768d7f2e76SPhilippe Mathieu-Daudé {
1877197faa70SPhilippe Mathieu-Daudé     if (!memory_region_init_ram_flags_nomigrate(mr, owner, name,
1878197faa70SPhilippe Mathieu-Daudé                                                 size, 0, errp)) {
1879197faa70SPhilippe Mathieu-Daudé          return false;
1880197faa70SPhilippe Mathieu-Daudé     }
18818d7f2e76SPhilippe Mathieu-Daudé     mr->readonly = true;
1882197faa70SPhilippe Mathieu-Daudé 
1883197faa70SPhilippe Mathieu-Daudé     return true;
18848d7f2e76SPhilippe Mathieu-Daudé }
18858d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_rom_device_nomigrate(MemoryRegion * mr,Object * owner,const MemoryRegionOps * ops,void * opaque,const char * name,uint64_t size,Error ** errp)1886ae076b6cSPhilippe Mathieu-Daudé bool memory_region_init_rom_device_nomigrate(MemoryRegion *mr,
18878d7f2e76SPhilippe Mathieu-Daudé                                              Object *owner,
18888d7f2e76SPhilippe Mathieu-Daudé                                              const MemoryRegionOps *ops,
18898d7f2e76SPhilippe Mathieu-Daudé                                              void *opaque,
18908d7f2e76SPhilippe Mathieu-Daudé                                              const char *name,
18918d7f2e76SPhilippe Mathieu-Daudé                                              uint64_t size,
18928d7f2e76SPhilippe Mathieu-Daudé                                              Error **errp)
18938d7f2e76SPhilippe Mathieu-Daudé {
18948d7f2e76SPhilippe Mathieu-Daudé     Error *err = NULL;
18958d7f2e76SPhilippe Mathieu-Daudé     assert(ops);
18968d7f2e76SPhilippe Mathieu-Daudé     memory_region_init(mr, owner, name, size);
18978d7f2e76SPhilippe Mathieu-Daudé     mr->ops = ops;
18988d7f2e76SPhilippe Mathieu-Daudé     mr->opaque = opaque;
18998d7f2e76SPhilippe Mathieu-Daudé     mr->terminates = true;
19008d7f2e76SPhilippe Mathieu-Daudé     mr->rom_device = true;
19018d7f2e76SPhilippe Mathieu-Daudé     mr->destructor = memory_region_destructor_ram;
19028d7f2e76SPhilippe Mathieu-Daudé     mr->ram_block = qemu_ram_alloc(size, 0, mr, &err);
19038d7f2e76SPhilippe Mathieu-Daudé     if (err) {
19048d7f2e76SPhilippe Mathieu-Daudé         mr->size = int128_zero();
19058d7f2e76SPhilippe Mathieu-Daudé         object_unparent(OBJECT(mr));
19068d7f2e76SPhilippe Mathieu-Daudé         error_propagate(errp, err);
1907ae076b6cSPhilippe Mathieu-Daudé         return false;
19088d7f2e76SPhilippe Mathieu-Daudé     }
1909ae076b6cSPhilippe Mathieu-Daudé     return true;
19108d7f2e76SPhilippe Mathieu-Daudé }
19118d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_iommu(void * _iommu_mr,size_t instance_size,const char * mrtypename,Object * owner,const char * name,uint64_t size)19128d7f2e76SPhilippe Mathieu-Daudé void memory_region_init_iommu(void *_iommu_mr,
19138d7f2e76SPhilippe Mathieu-Daudé                               size_t instance_size,
19148d7f2e76SPhilippe Mathieu-Daudé                               const char *mrtypename,
19158d7f2e76SPhilippe Mathieu-Daudé                               Object *owner,
19168d7f2e76SPhilippe Mathieu-Daudé                               const char *name,
19178d7f2e76SPhilippe Mathieu-Daudé                               uint64_t size)
19188d7f2e76SPhilippe Mathieu-Daudé {
19198d7f2e76SPhilippe Mathieu-Daudé     struct IOMMUMemoryRegion *iommu_mr;
19208d7f2e76SPhilippe Mathieu-Daudé     struct MemoryRegion *mr;
19218d7f2e76SPhilippe Mathieu-Daudé 
19228d7f2e76SPhilippe Mathieu-Daudé     object_initialize(_iommu_mr, instance_size, mrtypename);
19238d7f2e76SPhilippe Mathieu-Daudé     mr = MEMORY_REGION(_iommu_mr);
19248d7f2e76SPhilippe Mathieu-Daudé     memory_region_do_init(mr, owner, name, size);
19258d7f2e76SPhilippe Mathieu-Daudé     iommu_mr = IOMMU_MEMORY_REGION(mr);
19268d7f2e76SPhilippe Mathieu-Daudé     mr->terminates = true;  /* then re-forwards */
19278d7f2e76SPhilippe Mathieu-Daudé     QLIST_INIT(&iommu_mr->iommu_notify);
19288d7f2e76SPhilippe Mathieu-Daudé     iommu_mr->iommu_notify_flags = IOMMU_NOTIFIER_NONE;
19298d7f2e76SPhilippe Mathieu-Daudé }
19308d7f2e76SPhilippe Mathieu-Daudé 
memory_region_finalize(Object * obj)19318d7f2e76SPhilippe Mathieu-Daudé static void memory_region_finalize(Object *obj)
19328d7f2e76SPhilippe Mathieu-Daudé {
19338d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr = MEMORY_REGION(obj);
19348d7f2e76SPhilippe Mathieu-Daudé 
19358d7f2e76SPhilippe Mathieu-Daudé     assert(!mr->container);
19368d7f2e76SPhilippe Mathieu-Daudé 
19378d7f2e76SPhilippe Mathieu-Daudé     /* We know the region is not visible in any address space (it
19388d7f2e76SPhilippe Mathieu-Daudé      * does not have a container and cannot be a root either because
19398d7f2e76SPhilippe Mathieu-Daudé      * it has no references, so we can blindly clear mr->enabled.
19408d7f2e76SPhilippe Mathieu-Daudé      * memory_region_set_enabled instead could trigger a transaction
19418d7f2e76SPhilippe Mathieu-Daudé      * and cause an infinite loop.
19428d7f2e76SPhilippe Mathieu-Daudé      */
19438d7f2e76SPhilippe Mathieu-Daudé     mr->enabled = false;
19448d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_begin();
19458d7f2e76SPhilippe Mathieu-Daudé     while (!QTAILQ_EMPTY(&mr->subregions)) {
19468d7f2e76SPhilippe Mathieu-Daudé         MemoryRegion *subregion = QTAILQ_FIRST(&mr->subregions);
19478d7f2e76SPhilippe Mathieu-Daudé         memory_region_del_subregion(mr, subregion);
19488d7f2e76SPhilippe Mathieu-Daudé     }
19498d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_commit();
19508d7f2e76SPhilippe Mathieu-Daudé 
19518d7f2e76SPhilippe Mathieu-Daudé     mr->destructor(mr);
19528d7f2e76SPhilippe Mathieu-Daudé     memory_region_clear_coalescing(mr);
19538d7f2e76SPhilippe Mathieu-Daudé     g_free((char *)mr->name);
19548d7f2e76SPhilippe Mathieu-Daudé     g_free(mr->ioeventfds);
19558d7f2e76SPhilippe Mathieu-Daudé }
19568d7f2e76SPhilippe Mathieu-Daudé 
memory_region_owner(MemoryRegion * mr)19578d7f2e76SPhilippe Mathieu-Daudé Object *memory_region_owner(MemoryRegion *mr)
19588d7f2e76SPhilippe Mathieu-Daudé {
19598d7f2e76SPhilippe Mathieu-Daudé     Object *obj = OBJECT(mr);
19608d7f2e76SPhilippe Mathieu-Daudé     return obj->parent;
19618d7f2e76SPhilippe Mathieu-Daudé }
19628d7f2e76SPhilippe Mathieu-Daudé 
memory_region_ref(MemoryRegion * mr)19638d7f2e76SPhilippe Mathieu-Daudé void memory_region_ref(MemoryRegion *mr)
19648d7f2e76SPhilippe Mathieu-Daudé {
19658d7f2e76SPhilippe Mathieu-Daudé     /* MMIO callbacks most likely will access data that belongs
19668d7f2e76SPhilippe Mathieu-Daudé      * to the owner, hence the need to ref/unref the owner whenever
19678d7f2e76SPhilippe Mathieu-Daudé      * the memory region is in use.
19688d7f2e76SPhilippe Mathieu-Daudé      *
19698d7f2e76SPhilippe Mathieu-Daudé      * The memory region is a child of its owner.  As long as the
19708d7f2e76SPhilippe Mathieu-Daudé      * owner doesn't call unparent itself on the memory region,
19718d7f2e76SPhilippe Mathieu-Daudé      * ref-ing the owner will also keep the memory region alive.
19728d7f2e76SPhilippe Mathieu-Daudé      * Memory regions without an owner are supposed to never go away;
19738d7f2e76SPhilippe Mathieu-Daudé      * we do not ref/unref them because it slows down DMA sensibly.
19748d7f2e76SPhilippe Mathieu-Daudé      */
19758d7f2e76SPhilippe Mathieu-Daudé     if (mr && mr->owner) {
19768d7f2e76SPhilippe Mathieu-Daudé         object_ref(mr->owner);
19778d7f2e76SPhilippe Mathieu-Daudé     }
19788d7f2e76SPhilippe Mathieu-Daudé }
19798d7f2e76SPhilippe Mathieu-Daudé 
memory_region_unref(MemoryRegion * mr)19808d7f2e76SPhilippe Mathieu-Daudé void memory_region_unref(MemoryRegion *mr)
19818d7f2e76SPhilippe Mathieu-Daudé {
19828d7f2e76SPhilippe Mathieu-Daudé     if (mr && mr->owner) {
19838d7f2e76SPhilippe Mathieu-Daudé         object_unref(mr->owner);
19848d7f2e76SPhilippe Mathieu-Daudé     }
19858d7f2e76SPhilippe Mathieu-Daudé }
19868d7f2e76SPhilippe Mathieu-Daudé 
memory_region_size(MemoryRegion * mr)19878d7f2e76SPhilippe Mathieu-Daudé uint64_t memory_region_size(MemoryRegion *mr)
19888d7f2e76SPhilippe Mathieu-Daudé {
19898d7f2e76SPhilippe Mathieu-Daudé     if (int128_eq(mr->size, int128_2_64())) {
19908d7f2e76SPhilippe Mathieu-Daudé         return UINT64_MAX;
19918d7f2e76SPhilippe Mathieu-Daudé     }
19928d7f2e76SPhilippe Mathieu-Daudé     return int128_get64(mr->size);
19938d7f2e76SPhilippe Mathieu-Daudé }
19948d7f2e76SPhilippe Mathieu-Daudé 
memory_region_name(const MemoryRegion * mr)19958d7f2e76SPhilippe Mathieu-Daudé const char *memory_region_name(const MemoryRegion *mr)
19968d7f2e76SPhilippe Mathieu-Daudé {
19978d7f2e76SPhilippe Mathieu-Daudé     if (!mr->name) {
19988d7f2e76SPhilippe Mathieu-Daudé         ((MemoryRegion *)mr)->name =
19998d7f2e76SPhilippe Mathieu-Daudé             g_strdup(object_get_canonical_path_component(OBJECT(mr)));
20008d7f2e76SPhilippe Mathieu-Daudé     }
20018d7f2e76SPhilippe Mathieu-Daudé     return mr->name;
20028d7f2e76SPhilippe Mathieu-Daudé }
20038d7f2e76SPhilippe Mathieu-Daudé 
memory_region_is_ram_device(MemoryRegion * mr)20048d7f2e76SPhilippe Mathieu-Daudé bool memory_region_is_ram_device(MemoryRegion *mr)
20058d7f2e76SPhilippe Mathieu-Daudé {
20068d7f2e76SPhilippe Mathieu-Daudé     return mr->ram_device;
20078d7f2e76SPhilippe Mathieu-Daudé }
20088d7f2e76SPhilippe Mathieu-Daudé 
memory_region_is_protected(MemoryRegion * mr)20098d7f2e76SPhilippe Mathieu-Daudé bool memory_region_is_protected(MemoryRegion *mr)
20108d7f2e76SPhilippe Mathieu-Daudé {
20118d7f2e76SPhilippe Mathieu-Daudé     return mr->ram && (mr->ram_block->flags & RAM_PROTECTED);
20128d7f2e76SPhilippe Mathieu-Daudé }
20138d7f2e76SPhilippe Mathieu-Daudé 
memory_region_has_guest_memfd(MemoryRegion * mr)201415f7a80cSXiaoyao Li bool memory_region_has_guest_memfd(MemoryRegion *mr)
201515f7a80cSXiaoyao Li {
201615f7a80cSXiaoyao Li     return mr->ram_block && mr->ram_block->guest_memfd >= 0;
201715f7a80cSXiaoyao Li }
201815f7a80cSXiaoyao Li 
memory_region_get_dirty_log_mask(MemoryRegion * mr)20198d7f2e76SPhilippe Mathieu-Daudé uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr)
20208d7f2e76SPhilippe Mathieu-Daudé {
20218d7f2e76SPhilippe Mathieu-Daudé     uint8_t mask = mr->dirty_log_mask;
20228d7f2e76SPhilippe Mathieu-Daudé     RAMBlock *rb = mr->ram_block;
20238d7f2e76SPhilippe Mathieu-Daudé 
20248d7f2e76SPhilippe Mathieu-Daudé     if (global_dirty_tracking && ((rb && qemu_ram_is_migratable(rb)) ||
20258d7f2e76SPhilippe Mathieu-Daudé                              memory_region_is_iommu(mr))) {
20268d7f2e76SPhilippe Mathieu-Daudé         mask |= (1 << DIRTY_MEMORY_MIGRATION);
20278d7f2e76SPhilippe Mathieu-Daudé     }
20288d7f2e76SPhilippe Mathieu-Daudé 
20298d7f2e76SPhilippe Mathieu-Daudé     if (tcg_enabled() && rb) {
20308d7f2e76SPhilippe Mathieu-Daudé         /* TCG only cares about dirty memory logging for RAM, not IOMMU.  */
20318d7f2e76SPhilippe Mathieu-Daudé         mask |= (1 << DIRTY_MEMORY_CODE);
20328d7f2e76SPhilippe Mathieu-Daudé     }
20338d7f2e76SPhilippe Mathieu-Daudé     return mask;
20348d7f2e76SPhilippe Mathieu-Daudé }
20358d7f2e76SPhilippe Mathieu-Daudé 
memory_region_is_logging(MemoryRegion * mr,uint8_t client)20368d7f2e76SPhilippe Mathieu-Daudé bool memory_region_is_logging(MemoryRegion *mr, uint8_t client)
20378d7f2e76SPhilippe Mathieu-Daudé {
20388d7f2e76SPhilippe Mathieu-Daudé     return memory_region_get_dirty_log_mask(mr) & (1 << client);
20398d7f2e76SPhilippe Mathieu-Daudé }
20408d7f2e76SPhilippe Mathieu-Daudé 
memory_region_update_iommu_notify_flags(IOMMUMemoryRegion * iommu_mr,Error ** errp)20418d7f2e76SPhilippe Mathieu-Daudé static int memory_region_update_iommu_notify_flags(IOMMUMemoryRegion *iommu_mr,
20428d7f2e76SPhilippe Mathieu-Daudé                                                    Error **errp)
20438d7f2e76SPhilippe Mathieu-Daudé {
20448d7f2e76SPhilippe Mathieu-Daudé     IOMMUNotifierFlag flags = IOMMU_NOTIFIER_NONE;
20458d7f2e76SPhilippe Mathieu-Daudé     IOMMUNotifier *iommu_notifier;
20468d7f2e76SPhilippe Mathieu-Daudé     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
20478d7f2e76SPhilippe Mathieu-Daudé     int ret = 0;
20488d7f2e76SPhilippe Mathieu-Daudé 
20498d7f2e76SPhilippe Mathieu-Daudé     IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) {
20508d7f2e76SPhilippe Mathieu-Daudé         flags |= iommu_notifier->notifier_flags;
20518d7f2e76SPhilippe Mathieu-Daudé     }
20528d7f2e76SPhilippe Mathieu-Daudé 
20538d7f2e76SPhilippe Mathieu-Daudé     if (flags != iommu_mr->iommu_notify_flags && imrc->notify_flag_changed) {
20548d7f2e76SPhilippe Mathieu-Daudé         ret = imrc->notify_flag_changed(iommu_mr,
20558d7f2e76SPhilippe Mathieu-Daudé                                         iommu_mr->iommu_notify_flags,
20568d7f2e76SPhilippe Mathieu-Daudé                                         flags, errp);
20578d7f2e76SPhilippe Mathieu-Daudé     }
20588d7f2e76SPhilippe Mathieu-Daudé 
20598d7f2e76SPhilippe Mathieu-Daudé     if (!ret) {
20608d7f2e76SPhilippe Mathieu-Daudé         iommu_mr->iommu_notify_flags = flags;
20618d7f2e76SPhilippe Mathieu-Daudé     }
20628d7f2e76SPhilippe Mathieu-Daudé     return ret;
20638d7f2e76SPhilippe Mathieu-Daudé }
20648d7f2e76SPhilippe Mathieu-Daudé 
memory_region_register_iommu_notifier(MemoryRegion * mr,IOMMUNotifier * n,Error ** errp)20658d7f2e76SPhilippe Mathieu-Daudé int memory_region_register_iommu_notifier(MemoryRegion *mr,
20668d7f2e76SPhilippe Mathieu-Daudé                                           IOMMUNotifier *n, Error **errp)
20678d7f2e76SPhilippe Mathieu-Daudé {
20688d7f2e76SPhilippe Mathieu-Daudé     IOMMUMemoryRegion *iommu_mr;
20698d7f2e76SPhilippe Mathieu-Daudé     int ret;
20708d7f2e76SPhilippe Mathieu-Daudé 
20718d7f2e76SPhilippe Mathieu-Daudé     if (mr->alias) {
20728d7f2e76SPhilippe Mathieu-Daudé         return memory_region_register_iommu_notifier(mr->alias, n, errp);
20738d7f2e76SPhilippe Mathieu-Daudé     }
20748d7f2e76SPhilippe Mathieu-Daudé 
20758d7f2e76SPhilippe Mathieu-Daudé     /* We need to register for at least one bitfield */
20768d7f2e76SPhilippe Mathieu-Daudé     iommu_mr = IOMMU_MEMORY_REGION(mr);
20778d7f2e76SPhilippe Mathieu-Daudé     assert(n->notifier_flags != IOMMU_NOTIFIER_NONE);
20788d7f2e76SPhilippe Mathieu-Daudé     assert(n->start <= n->end);
20798d7f2e76SPhilippe Mathieu-Daudé     assert(n->iommu_idx >= 0 &&
20808d7f2e76SPhilippe Mathieu-Daudé            n->iommu_idx < memory_region_iommu_num_indexes(iommu_mr));
20818d7f2e76SPhilippe Mathieu-Daudé 
20828d7f2e76SPhilippe Mathieu-Daudé     QLIST_INSERT_HEAD(&iommu_mr->iommu_notify, n, node);
20838d7f2e76SPhilippe Mathieu-Daudé     ret = memory_region_update_iommu_notify_flags(iommu_mr, errp);
20848d7f2e76SPhilippe Mathieu-Daudé     if (ret) {
20858d7f2e76SPhilippe Mathieu-Daudé         QLIST_REMOVE(n, node);
20868d7f2e76SPhilippe Mathieu-Daudé     }
20878d7f2e76SPhilippe Mathieu-Daudé     return ret;
20888d7f2e76SPhilippe Mathieu-Daudé }
20898d7f2e76SPhilippe Mathieu-Daudé 
memory_region_iommu_get_min_page_size(IOMMUMemoryRegion * iommu_mr)20908d7f2e76SPhilippe Mathieu-Daudé uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr)
20918d7f2e76SPhilippe Mathieu-Daudé {
20928d7f2e76SPhilippe Mathieu-Daudé     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
20938d7f2e76SPhilippe Mathieu-Daudé 
20948d7f2e76SPhilippe Mathieu-Daudé     if (imrc->get_min_page_size) {
20958d7f2e76SPhilippe Mathieu-Daudé         return imrc->get_min_page_size(iommu_mr);
20968d7f2e76SPhilippe Mathieu-Daudé     }
20978d7f2e76SPhilippe Mathieu-Daudé     return TARGET_PAGE_SIZE;
20988d7f2e76SPhilippe Mathieu-Daudé }
20998d7f2e76SPhilippe Mathieu-Daudé 
memory_region_iommu_replay(IOMMUMemoryRegion * iommu_mr,IOMMUNotifier * n)21008d7f2e76SPhilippe Mathieu-Daudé void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
21018d7f2e76SPhilippe Mathieu-Daudé {
21028d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr = MEMORY_REGION(iommu_mr);
21038d7f2e76SPhilippe Mathieu-Daudé     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
21048d7f2e76SPhilippe Mathieu-Daudé     hwaddr addr, granularity;
21058d7f2e76SPhilippe Mathieu-Daudé     IOMMUTLBEntry iotlb;
21068d7f2e76SPhilippe Mathieu-Daudé 
21078d7f2e76SPhilippe Mathieu-Daudé     /* If the IOMMU has its own replay callback, override */
21088d7f2e76SPhilippe Mathieu-Daudé     if (imrc->replay) {
21098d7f2e76SPhilippe Mathieu-Daudé         imrc->replay(iommu_mr, n);
21108d7f2e76SPhilippe Mathieu-Daudé         return;
21118d7f2e76SPhilippe Mathieu-Daudé     }
21128d7f2e76SPhilippe Mathieu-Daudé 
21138d7f2e76SPhilippe Mathieu-Daudé     granularity = memory_region_iommu_get_min_page_size(iommu_mr);
21148d7f2e76SPhilippe Mathieu-Daudé 
21158d7f2e76SPhilippe Mathieu-Daudé     for (addr = 0; addr < memory_region_size(mr); addr += granularity) {
21168d7f2e76SPhilippe Mathieu-Daudé         iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE, n->iommu_idx);
21178d7f2e76SPhilippe Mathieu-Daudé         if (iotlb.perm != IOMMU_NONE) {
21188d7f2e76SPhilippe Mathieu-Daudé             n->notify(n, &iotlb);
21198d7f2e76SPhilippe Mathieu-Daudé         }
21208d7f2e76SPhilippe Mathieu-Daudé 
21218d7f2e76SPhilippe Mathieu-Daudé         /* if (2^64 - MR size) < granularity, it's possible to get an
21228d7f2e76SPhilippe Mathieu-Daudé          * infinite loop here.  This should catch such a wraparound */
21238d7f2e76SPhilippe Mathieu-Daudé         if ((addr + granularity) < addr) {
21248d7f2e76SPhilippe Mathieu-Daudé             break;
21258d7f2e76SPhilippe Mathieu-Daudé         }
21268d7f2e76SPhilippe Mathieu-Daudé     }
21278d7f2e76SPhilippe Mathieu-Daudé }
21288d7f2e76SPhilippe Mathieu-Daudé 
memory_region_unregister_iommu_notifier(MemoryRegion * mr,IOMMUNotifier * n)21298d7f2e76SPhilippe Mathieu-Daudé void memory_region_unregister_iommu_notifier(MemoryRegion *mr,
21308d7f2e76SPhilippe Mathieu-Daudé                                              IOMMUNotifier *n)
21318d7f2e76SPhilippe Mathieu-Daudé {
21328d7f2e76SPhilippe Mathieu-Daudé     IOMMUMemoryRegion *iommu_mr;
21338d7f2e76SPhilippe Mathieu-Daudé 
21348d7f2e76SPhilippe Mathieu-Daudé     if (mr->alias) {
21358d7f2e76SPhilippe Mathieu-Daudé         memory_region_unregister_iommu_notifier(mr->alias, n);
21368d7f2e76SPhilippe Mathieu-Daudé         return;
21378d7f2e76SPhilippe Mathieu-Daudé     }
21388d7f2e76SPhilippe Mathieu-Daudé     QLIST_REMOVE(n, node);
21398d7f2e76SPhilippe Mathieu-Daudé     iommu_mr = IOMMU_MEMORY_REGION(mr);
21408d7f2e76SPhilippe Mathieu-Daudé     memory_region_update_iommu_notify_flags(iommu_mr, NULL);
21418d7f2e76SPhilippe Mathieu-Daudé }
21428d7f2e76SPhilippe Mathieu-Daudé 
memory_region_notify_iommu_one(IOMMUNotifier * notifier,const IOMMUTLBEvent * event)21438d7f2e76SPhilippe Mathieu-Daudé void memory_region_notify_iommu_one(IOMMUNotifier *notifier,
2144ec40be99SPhilippe Mathieu-Daudé                                     const IOMMUTLBEvent *event)
21458d7f2e76SPhilippe Mathieu-Daudé {
2146ec40be99SPhilippe Mathieu-Daudé     const IOMMUTLBEntry *entry = &event->entry;
21478d7f2e76SPhilippe Mathieu-Daudé     hwaddr entry_end = entry->iova + entry->addr_mask;
21488d7f2e76SPhilippe Mathieu-Daudé     IOMMUTLBEntry tmp = *entry;
21498d7f2e76SPhilippe Mathieu-Daudé 
21508d7f2e76SPhilippe Mathieu-Daudé     if (event->type == IOMMU_NOTIFIER_UNMAP) {
21518d7f2e76SPhilippe Mathieu-Daudé         assert(entry->perm == IOMMU_NONE);
21528d7f2e76SPhilippe Mathieu-Daudé     }
21538d7f2e76SPhilippe Mathieu-Daudé 
21548d7f2e76SPhilippe Mathieu-Daudé     /*
21558d7f2e76SPhilippe Mathieu-Daudé      * Skip the notification if the notification does not overlap
21568d7f2e76SPhilippe Mathieu-Daudé      * with registered range.
21578d7f2e76SPhilippe Mathieu-Daudé      */
21588d7f2e76SPhilippe Mathieu-Daudé     if (notifier->start > entry_end || notifier->end < entry->iova) {
21598d7f2e76SPhilippe Mathieu-Daudé         return;
21608d7f2e76SPhilippe Mathieu-Daudé     }
21618d7f2e76SPhilippe Mathieu-Daudé 
21628d7f2e76SPhilippe Mathieu-Daudé     if (notifier->notifier_flags & IOMMU_NOTIFIER_DEVIOTLB_UNMAP) {
21638d7f2e76SPhilippe Mathieu-Daudé         /* Crop (iova, addr_mask) to range */
21648d7f2e76SPhilippe Mathieu-Daudé         tmp.iova = MAX(tmp.iova, notifier->start);
21658d7f2e76SPhilippe Mathieu-Daudé         tmp.addr_mask = MIN(entry_end, notifier->end) - tmp.iova;
21668d7f2e76SPhilippe Mathieu-Daudé     } else {
21678d7f2e76SPhilippe Mathieu-Daudé         assert(entry->iova >= notifier->start && entry_end <= notifier->end);
21688d7f2e76SPhilippe Mathieu-Daudé     }
21698d7f2e76SPhilippe Mathieu-Daudé 
21708d7f2e76SPhilippe Mathieu-Daudé     if (event->type & notifier->notifier_flags) {
21718d7f2e76SPhilippe Mathieu-Daudé         notifier->notify(notifier, &tmp);
21728d7f2e76SPhilippe Mathieu-Daudé     }
21738d7f2e76SPhilippe Mathieu-Daudé }
21748d7f2e76SPhilippe Mathieu-Daudé 
memory_region_unmap_iommu_notifier_range(IOMMUNotifier * notifier)21758d7f2e76SPhilippe Mathieu-Daudé void memory_region_unmap_iommu_notifier_range(IOMMUNotifier *notifier)
21768d7f2e76SPhilippe Mathieu-Daudé {
21778d7f2e76SPhilippe Mathieu-Daudé     IOMMUTLBEvent event;
21788d7f2e76SPhilippe Mathieu-Daudé 
21798d7f2e76SPhilippe Mathieu-Daudé     event.type = IOMMU_NOTIFIER_UNMAP;
21808d7f2e76SPhilippe Mathieu-Daudé     event.entry.target_as = &address_space_memory;
21818d7f2e76SPhilippe Mathieu-Daudé     event.entry.iova = notifier->start;
21828d7f2e76SPhilippe Mathieu-Daudé     event.entry.perm = IOMMU_NONE;
21838d7f2e76SPhilippe Mathieu-Daudé     event.entry.addr_mask = notifier->end - notifier->start;
21848d7f2e76SPhilippe Mathieu-Daudé 
21858d7f2e76SPhilippe Mathieu-Daudé     memory_region_notify_iommu_one(notifier, &event);
21868d7f2e76SPhilippe Mathieu-Daudé }
21878d7f2e76SPhilippe Mathieu-Daudé 
memory_region_notify_iommu(IOMMUMemoryRegion * iommu_mr,int iommu_idx,const IOMMUTLBEvent event)21888d7f2e76SPhilippe Mathieu-Daudé void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
21898d7f2e76SPhilippe Mathieu-Daudé                                 int iommu_idx,
2190eb5b2896SPhilippe Mathieu-Daudé                                 const IOMMUTLBEvent event)
21918d7f2e76SPhilippe Mathieu-Daudé {
21928d7f2e76SPhilippe Mathieu-Daudé     IOMMUNotifier *iommu_notifier;
21938d7f2e76SPhilippe Mathieu-Daudé 
21948d7f2e76SPhilippe Mathieu-Daudé     assert(memory_region_is_iommu(MEMORY_REGION(iommu_mr)));
21958d7f2e76SPhilippe Mathieu-Daudé 
21968d7f2e76SPhilippe Mathieu-Daudé     IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) {
21978d7f2e76SPhilippe Mathieu-Daudé         if (iommu_notifier->iommu_idx == iommu_idx) {
21988d7f2e76SPhilippe Mathieu-Daudé             memory_region_notify_iommu_one(iommu_notifier, &event);
21998d7f2e76SPhilippe Mathieu-Daudé         }
22008d7f2e76SPhilippe Mathieu-Daudé     }
22018d7f2e76SPhilippe Mathieu-Daudé }
22028d7f2e76SPhilippe Mathieu-Daudé 
memory_region_iommu_get_attr(IOMMUMemoryRegion * iommu_mr,enum IOMMUMemoryRegionAttr attr,void * data)22038d7f2e76SPhilippe Mathieu-Daudé int memory_region_iommu_get_attr(IOMMUMemoryRegion *iommu_mr,
22048d7f2e76SPhilippe Mathieu-Daudé                                  enum IOMMUMemoryRegionAttr attr,
22058d7f2e76SPhilippe Mathieu-Daudé                                  void *data)
22068d7f2e76SPhilippe Mathieu-Daudé {
22078d7f2e76SPhilippe Mathieu-Daudé     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
22088d7f2e76SPhilippe Mathieu-Daudé 
22098d7f2e76SPhilippe Mathieu-Daudé     if (!imrc->get_attr) {
22108d7f2e76SPhilippe Mathieu-Daudé         return -EINVAL;
22118d7f2e76SPhilippe Mathieu-Daudé     }
22128d7f2e76SPhilippe Mathieu-Daudé 
22138d7f2e76SPhilippe Mathieu-Daudé     return imrc->get_attr(iommu_mr, attr, data);
22148d7f2e76SPhilippe Mathieu-Daudé }
22158d7f2e76SPhilippe Mathieu-Daudé 
memory_region_iommu_attrs_to_index(IOMMUMemoryRegion * iommu_mr,MemTxAttrs attrs)22168d7f2e76SPhilippe Mathieu-Daudé int memory_region_iommu_attrs_to_index(IOMMUMemoryRegion *iommu_mr,
22178d7f2e76SPhilippe Mathieu-Daudé                                        MemTxAttrs attrs)
22188d7f2e76SPhilippe Mathieu-Daudé {
22198d7f2e76SPhilippe Mathieu-Daudé     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
22208d7f2e76SPhilippe Mathieu-Daudé 
22218d7f2e76SPhilippe Mathieu-Daudé     if (!imrc->attrs_to_index) {
22228d7f2e76SPhilippe Mathieu-Daudé         return 0;
22238d7f2e76SPhilippe Mathieu-Daudé     }
22248d7f2e76SPhilippe Mathieu-Daudé 
22258d7f2e76SPhilippe Mathieu-Daudé     return imrc->attrs_to_index(iommu_mr, attrs);
22268d7f2e76SPhilippe Mathieu-Daudé }
22278d7f2e76SPhilippe Mathieu-Daudé 
memory_region_iommu_num_indexes(IOMMUMemoryRegion * iommu_mr)22288d7f2e76SPhilippe Mathieu-Daudé int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr)
22298d7f2e76SPhilippe Mathieu-Daudé {
22308d7f2e76SPhilippe Mathieu-Daudé     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
22318d7f2e76SPhilippe Mathieu-Daudé 
22328d7f2e76SPhilippe Mathieu-Daudé     if (!imrc->num_indexes) {
22338d7f2e76SPhilippe Mathieu-Daudé         return 1;
22348d7f2e76SPhilippe Mathieu-Daudé     }
22358d7f2e76SPhilippe Mathieu-Daudé 
22368d7f2e76SPhilippe Mathieu-Daudé     return imrc->num_indexes(iommu_mr);
22378d7f2e76SPhilippe Mathieu-Daudé }
22388d7f2e76SPhilippe Mathieu-Daudé 
memory_region_get_ram_discard_manager(MemoryRegion * mr)22398d7f2e76SPhilippe Mathieu-Daudé RamDiscardManager *memory_region_get_ram_discard_manager(MemoryRegion *mr)
22408d7f2e76SPhilippe Mathieu-Daudé {
2241aa5317efSDavid Hildenbrand     if (!memory_region_is_ram(mr)) {
22428d7f2e76SPhilippe Mathieu-Daudé         return NULL;
22438d7f2e76SPhilippe Mathieu-Daudé     }
22448d7f2e76SPhilippe Mathieu-Daudé     return mr->rdm;
22458d7f2e76SPhilippe Mathieu-Daudé }
22468d7f2e76SPhilippe Mathieu-Daudé 
memory_region_set_ram_discard_manager(MemoryRegion * mr,RamDiscardManager * rdm)22478d7f2e76SPhilippe Mathieu-Daudé void memory_region_set_ram_discard_manager(MemoryRegion *mr,
22488d7f2e76SPhilippe Mathieu-Daudé                                            RamDiscardManager *rdm)
22498d7f2e76SPhilippe Mathieu-Daudé {
2250aa5317efSDavid Hildenbrand     g_assert(memory_region_is_ram(mr));
22518d7f2e76SPhilippe Mathieu-Daudé     g_assert(!rdm || !mr->rdm);
22528d7f2e76SPhilippe Mathieu-Daudé     mr->rdm = rdm;
22538d7f2e76SPhilippe Mathieu-Daudé }
22548d7f2e76SPhilippe Mathieu-Daudé 
ram_discard_manager_get_min_granularity(const RamDiscardManager * rdm,const MemoryRegion * mr)22558d7f2e76SPhilippe Mathieu-Daudé uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *rdm,
22568d7f2e76SPhilippe Mathieu-Daudé                                                  const MemoryRegion *mr)
22578d7f2e76SPhilippe Mathieu-Daudé {
22588d7f2e76SPhilippe Mathieu-Daudé     RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
22598d7f2e76SPhilippe Mathieu-Daudé 
22608d7f2e76SPhilippe Mathieu-Daudé     g_assert(rdmc->get_min_granularity);
22618d7f2e76SPhilippe Mathieu-Daudé     return rdmc->get_min_granularity(rdm, mr);
22628d7f2e76SPhilippe Mathieu-Daudé }
22638d7f2e76SPhilippe Mathieu-Daudé 
ram_discard_manager_is_populated(const RamDiscardManager * rdm,const MemoryRegionSection * section)22648d7f2e76SPhilippe Mathieu-Daudé bool ram_discard_manager_is_populated(const RamDiscardManager *rdm,
22658d7f2e76SPhilippe Mathieu-Daudé                                       const MemoryRegionSection *section)
22668d7f2e76SPhilippe Mathieu-Daudé {
22678d7f2e76SPhilippe Mathieu-Daudé     RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
22688d7f2e76SPhilippe Mathieu-Daudé 
22698d7f2e76SPhilippe Mathieu-Daudé     g_assert(rdmc->is_populated);
22708d7f2e76SPhilippe Mathieu-Daudé     return rdmc->is_populated(rdm, section);
22718d7f2e76SPhilippe Mathieu-Daudé }
22728d7f2e76SPhilippe Mathieu-Daudé 
ram_discard_manager_replay_populated(const RamDiscardManager * rdm,MemoryRegionSection * section,ReplayRamPopulate replay_fn,void * opaque)22738d7f2e76SPhilippe Mathieu-Daudé int ram_discard_manager_replay_populated(const RamDiscardManager *rdm,
22748d7f2e76SPhilippe Mathieu-Daudé                                          MemoryRegionSection *section,
22758d7f2e76SPhilippe Mathieu-Daudé                                          ReplayRamPopulate replay_fn,
22768d7f2e76SPhilippe Mathieu-Daudé                                          void *opaque)
22778d7f2e76SPhilippe Mathieu-Daudé {
22788d7f2e76SPhilippe Mathieu-Daudé     RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
22798d7f2e76SPhilippe Mathieu-Daudé 
22808d7f2e76SPhilippe Mathieu-Daudé     g_assert(rdmc->replay_populated);
22818d7f2e76SPhilippe Mathieu-Daudé     return rdmc->replay_populated(rdm, section, replay_fn, opaque);
22828d7f2e76SPhilippe Mathieu-Daudé }
22838d7f2e76SPhilippe Mathieu-Daudé 
ram_discard_manager_replay_discarded(const RamDiscardManager * rdm,MemoryRegionSection * section,ReplayRamDiscard replay_fn,void * opaque)22848d7f2e76SPhilippe Mathieu-Daudé void ram_discard_manager_replay_discarded(const RamDiscardManager *rdm,
22858d7f2e76SPhilippe Mathieu-Daudé                                           MemoryRegionSection *section,
22868d7f2e76SPhilippe Mathieu-Daudé                                           ReplayRamDiscard replay_fn,
22878d7f2e76SPhilippe Mathieu-Daudé                                           void *opaque)
22888d7f2e76SPhilippe Mathieu-Daudé {
22898d7f2e76SPhilippe Mathieu-Daudé     RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
22908d7f2e76SPhilippe Mathieu-Daudé 
22918d7f2e76SPhilippe Mathieu-Daudé     g_assert(rdmc->replay_discarded);
22928d7f2e76SPhilippe Mathieu-Daudé     rdmc->replay_discarded(rdm, section, replay_fn, opaque);
22938d7f2e76SPhilippe Mathieu-Daudé }
22948d7f2e76SPhilippe Mathieu-Daudé 
ram_discard_manager_register_listener(RamDiscardManager * rdm,RamDiscardListener * rdl,MemoryRegionSection * section)22958d7f2e76SPhilippe Mathieu-Daudé void ram_discard_manager_register_listener(RamDiscardManager *rdm,
22968d7f2e76SPhilippe Mathieu-Daudé                                            RamDiscardListener *rdl,
22978d7f2e76SPhilippe Mathieu-Daudé                                            MemoryRegionSection *section)
22988d7f2e76SPhilippe Mathieu-Daudé {
22998d7f2e76SPhilippe Mathieu-Daudé     RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
23008d7f2e76SPhilippe Mathieu-Daudé 
23018d7f2e76SPhilippe Mathieu-Daudé     g_assert(rdmc->register_listener);
23028d7f2e76SPhilippe Mathieu-Daudé     rdmc->register_listener(rdm, rdl, section);
23038d7f2e76SPhilippe Mathieu-Daudé }
23048d7f2e76SPhilippe Mathieu-Daudé 
ram_discard_manager_unregister_listener(RamDiscardManager * rdm,RamDiscardListener * rdl)23058d7f2e76SPhilippe Mathieu-Daudé void ram_discard_manager_unregister_listener(RamDiscardManager *rdm,
23068d7f2e76SPhilippe Mathieu-Daudé                                              RamDiscardListener *rdl)
23078d7f2e76SPhilippe Mathieu-Daudé {
23088d7f2e76SPhilippe Mathieu-Daudé     RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
23098d7f2e76SPhilippe Mathieu-Daudé 
23108d7f2e76SPhilippe Mathieu-Daudé     g_assert(rdmc->unregister_listener);
23118d7f2e76SPhilippe Mathieu-Daudé     rdmc->unregister_listener(rdm, rdl);
23128d7f2e76SPhilippe Mathieu-Daudé }
23138d7f2e76SPhilippe Mathieu-Daudé 
23148d7f2e76SPhilippe Mathieu-Daudé /* Called with rcu_read_lock held.  */
memory_get_xlat_addr(IOMMUTLBEntry * iotlb,void ** vaddr,ram_addr_t * ram_addr,bool * read_only,bool * mr_has_discard_manager,Error ** errp)23158d7f2e76SPhilippe Mathieu-Daudé bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr,
23168d7f2e76SPhilippe Mathieu-Daudé                           ram_addr_t *ram_addr, bool *read_only,
2317ebb481c0SCédric Le Goater                           bool *mr_has_discard_manager, Error **errp)
23188d7f2e76SPhilippe Mathieu-Daudé {
23198d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr;
23208d7f2e76SPhilippe Mathieu-Daudé     hwaddr xlat;
23218d7f2e76SPhilippe Mathieu-Daudé     hwaddr len = iotlb->addr_mask + 1;
23228d7f2e76SPhilippe Mathieu-Daudé     bool writable = iotlb->perm & IOMMU_WO;
23238d7f2e76SPhilippe Mathieu-Daudé 
23248d7f2e76SPhilippe Mathieu-Daudé     if (mr_has_discard_manager) {
23258d7f2e76SPhilippe Mathieu-Daudé         *mr_has_discard_manager = false;
23268d7f2e76SPhilippe Mathieu-Daudé     }
23278d7f2e76SPhilippe Mathieu-Daudé     /*
23288d7f2e76SPhilippe Mathieu-Daudé      * The IOMMU TLB entry we have just covers translation through
23298d7f2e76SPhilippe Mathieu-Daudé      * this IOMMU to its immediate target.  We need to translate
23308d7f2e76SPhilippe Mathieu-Daudé      * it the rest of the way through to memory.
23318d7f2e76SPhilippe Mathieu-Daudé      */
23328d7f2e76SPhilippe Mathieu-Daudé     mr = address_space_translate(&address_space_memory, iotlb->translated_addr,
23338d7f2e76SPhilippe Mathieu-Daudé                                  &xlat, &len, writable, MEMTXATTRS_UNSPECIFIED);
23348d7f2e76SPhilippe Mathieu-Daudé     if (!memory_region_is_ram(mr)) {
2335ebb481c0SCédric Le Goater         error_setg(errp, "iommu map to non memory area %" HWADDR_PRIx "", xlat);
23368d7f2e76SPhilippe Mathieu-Daudé         return false;
23378d7f2e76SPhilippe Mathieu-Daudé     } else if (memory_region_has_ram_discard_manager(mr)) {
23388d7f2e76SPhilippe Mathieu-Daudé         RamDiscardManager *rdm = memory_region_get_ram_discard_manager(mr);
23398d7f2e76SPhilippe Mathieu-Daudé         MemoryRegionSection tmp = {
23408d7f2e76SPhilippe Mathieu-Daudé             .mr = mr,
23418d7f2e76SPhilippe Mathieu-Daudé             .offset_within_region = xlat,
23428d7f2e76SPhilippe Mathieu-Daudé             .size = int128_make64(len),
23438d7f2e76SPhilippe Mathieu-Daudé         };
23448d7f2e76SPhilippe Mathieu-Daudé         if (mr_has_discard_manager) {
23458d7f2e76SPhilippe Mathieu-Daudé             *mr_has_discard_manager = true;
23468d7f2e76SPhilippe Mathieu-Daudé         }
23478d7f2e76SPhilippe Mathieu-Daudé         /*
23488d7f2e76SPhilippe Mathieu-Daudé          * Malicious VMs can map memory into the IOMMU, which is expected
23498d7f2e76SPhilippe Mathieu-Daudé          * to remain discarded. vfio will pin all pages, populating memory.
23508d7f2e76SPhilippe Mathieu-Daudé          * Disallow that. vmstate priorities make sure any RamDiscardManager
23518d7f2e76SPhilippe Mathieu-Daudé          * were already restored before IOMMUs are restored.
23528d7f2e76SPhilippe Mathieu-Daudé          */
23538d7f2e76SPhilippe Mathieu-Daudé         if (!ram_discard_manager_is_populated(rdm, &tmp)) {
2354ebb481c0SCédric Le Goater             error_setg(errp, "iommu map to discarded memory (e.g., unplugged"
2355ebb481c0SCédric Le Goater                          " via virtio-mem): %" HWADDR_PRIx "",
23568d7f2e76SPhilippe Mathieu-Daudé                          iotlb->translated_addr);
23578d7f2e76SPhilippe Mathieu-Daudé             return false;
23588d7f2e76SPhilippe Mathieu-Daudé         }
23598d7f2e76SPhilippe Mathieu-Daudé     }
23608d7f2e76SPhilippe Mathieu-Daudé 
23618d7f2e76SPhilippe Mathieu-Daudé     /*
23628d7f2e76SPhilippe Mathieu-Daudé      * Translation truncates length to the IOMMU page size,
23638d7f2e76SPhilippe Mathieu-Daudé      * check that it did not truncate too much.
23648d7f2e76SPhilippe Mathieu-Daudé      */
23658d7f2e76SPhilippe Mathieu-Daudé     if (len & iotlb->addr_mask) {
2366ebb481c0SCédric Le Goater         error_setg(errp, "iommu has granularity incompatible with target AS");
23678d7f2e76SPhilippe Mathieu-Daudé         return false;
23688d7f2e76SPhilippe Mathieu-Daudé     }
23698d7f2e76SPhilippe Mathieu-Daudé 
23708d7f2e76SPhilippe Mathieu-Daudé     if (vaddr) {
23718d7f2e76SPhilippe Mathieu-Daudé         *vaddr = memory_region_get_ram_ptr(mr) + xlat;
23728d7f2e76SPhilippe Mathieu-Daudé     }
23738d7f2e76SPhilippe Mathieu-Daudé 
23748d7f2e76SPhilippe Mathieu-Daudé     if (ram_addr) {
23758d7f2e76SPhilippe Mathieu-Daudé         *ram_addr = memory_region_get_ram_addr(mr) + xlat;
23768d7f2e76SPhilippe Mathieu-Daudé     }
23778d7f2e76SPhilippe Mathieu-Daudé 
23788d7f2e76SPhilippe Mathieu-Daudé     if (read_only) {
23798d7f2e76SPhilippe Mathieu-Daudé         *read_only = !writable || mr->readonly;
23808d7f2e76SPhilippe Mathieu-Daudé     }
23818d7f2e76SPhilippe Mathieu-Daudé 
23828d7f2e76SPhilippe Mathieu-Daudé     return true;
23838d7f2e76SPhilippe Mathieu-Daudé }
23848d7f2e76SPhilippe Mathieu-Daudé 
memory_region_set_log(MemoryRegion * mr,bool log,unsigned client)23858d7f2e76SPhilippe Mathieu-Daudé void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
23868d7f2e76SPhilippe Mathieu-Daudé {
23878d7f2e76SPhilippe Mathieu-Daudé     uint8_t mask = 1 << client;
23888d7f2e76SPhilippe Mathieu-Daudé     uint8_t old_logging;
23898d7f2e76SPhilippe Mathieu-Daudé 
23908d7f2e76SPhilippe Mathieu-Daudé     assert(client == DIRTY_MEMORY_VGA);
23918d7f2e76SPhilippe Mathieu-Daudé     old_logging = mr->vga_logging_count;
23928d7f2e76SPhilippe Mathieu-Daudé     mr->vga_logging_count += log ? 1 : -1;
23938d7f2e76SPhilippe Mathieu-Daudé     if (!!old_logging == !!mr->vga_logging_count) {
23948d7f2e76SPhilippe Mathieu-Daudé         return;
23958d7f2e76SPhilippe Mathieu-Daudé     }
23968d7f2e76SPhilippe Mathieu-Daudé 
23978d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_begin();
23988d7f2e76SPhilippe Mathieu-Daudé     mr->dirty_log_mask = (mr->dirty_log_mask & ~mask) | (log * mask);
23998d7f2e76SPhilippe Mathieu-Daudé     memory_region_update_pending |= mr->enabled;
24008d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_commit();
24018d7f2e76SPhilippe Mathieu-Daudé }
24028d7f2e76SPhilippe Mathieu-Daudé 
memory_region_set_dirty(MemoryRegion * mr,hwaddr addr,hwaddr size)24038d7f2e76SPhilippe Mathieu-Daudé void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr,
24048d7f2e76SPhilippe Mathieu-Daudé                              hwaddr size)
24058d7f2e76SPhilippe Mathieu-Daudé {
24068d7f2e76SPhilippe Mathieu-Daudé     assert(mr->ram_block);
24078d7f2e76SPhilippe Mathieu-Daudé     cpu_physical_memory_set_dirty_range(memory_region_get_ram_addr(mr) + addr,
24088d7f2e76SPhilippe Mathieu-Daudé                                         size,
24098d7f2e76SPhilippe Mathieu-Daudé                                         memory_region_get_dirty_log_mask(mr));
24108d7f2e76SPhilippe Mathieu-Daudé }
24118d7f2e76SPhilippe Mathieu-Daudé 
24128d7f2e76SPhilippe Mathieu-Daudé /*
24138d7f2e76SPhilippe Mathieu-Daudé  * If memory region `mr' is NULL, do global sync.  Otherwise, sync
24148d7f2e76SPhilippe Mathieu-Daudé  * dirty bitmap for the specified memory region.
24158d7f2e76SPhilippe Mathieu-Daudé  */
memory_region_sync_dirty_bitmap(MemoryRegion * mr,bool last_stage)24168d7f2e76SPhilippe Mathieu-Daudé static void memory_region_sync_dirty_bitmap(MemoryRegion *mr, bool last_stage)
24178d7f2e76SPhilippe Mathieu-Daudé {
24188d7f2e76SPhilippe Mathieu-Daudé     MemoryListener *listener;
24198d7f2e76SPhilippe Mathieu-Daudé     AddressSpace *as;
24208d7f2e76SPhilippe Mathieu-Daudé     FlatView *view;
24218d7f2e76SPhilippe Mathieu-Daudé     FlatRange *fr;
24228d7f2e76SPhilippe Mathieu-Daudé 
24238d7f2e76SPhilippe Mathieu-Daudé     /* If the same address space has multiple log_sync listeners, we
24248d7f2e76SPhilippe Mathieu-Daudé      * visit that address space's FlatView multiple times.  But because
24258d7f2e76SPhilippe Mathieu-Daudé      * log_sync listeners are rare, it's still cheaper than walking each
24268d7f2e76SPhilippe Mathieu-Daudé      * address space once.
24278d7f2e76SPhilippe Mathieu-Daudé      */
24288d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(listener, &memory_listeners, link) {
24298d7f2e76SPhilippe Mathieu-Daudé         if (listener->log_sync) {
24308d7f2e76SPhilippe Mathieu-Daudé             as = listener->address_space;
24318d7f2e76SPhilippe Mathieu-Daudé             view = address_space_get_flatview(as);
24328d7f2e76SPhilippe Mathieu-Daudé             FOR_EACH_FLAT_RANGE(fr, view) {
24338d7f2e76SPhilippe Mathieu-Daudé                 if (fr->dirty_log_mask && (!mr || fr->mr == mr)) {
24348d7f2e76SPhilippe Mathieu-Daudé                     MemoryRegionSection mrs = section_from_flat_range(fr, view);
24358d7f2e76SPhilippe Mathieu-Daudé                     listener->log_sync(listener, &mrs);
24368d7f2e76SPhilippe Mathieu-Daudé                 }
24378d7f2e76SPhilippe Mathieu-Daudé             }
24388d7f2e76SPhilippe Mathieu-Daudé             flatview_unref(view);
24398d7f2e76SPhilippe Mathieu-Daudé             trace_memory_region_sync_dirty(mr ? mr->name : "(all)", listener->name, 0);
24408d7f2e76SPhilippe Mathieu-Daudé         } else if (listener->log_sync_global) {
24418d7f2e76SPhilippe Mathieu-Daudé             /*
24428d7f2e76SPhilippe Mathieu-Daudé              * No matter whether MR is specified, what we can do here
24438d7f2e76SPhilippe Mathieu-Daudé              * is to do a global sync, because we are not capable to
24448d7f2e76SPhilippe Mathieu-Daudé              * sync in a finer granularity.
24458d7f2e76SPhilippe Mathieu-Daudé              */
24468d7f2e76SPhilippe Mathieu-Daudé             listener->log_sync_global(listener, last_stage);
24478d7f2e76SPhilippe Mathieu-Daudé             trace_memory_region_sync_dirty(mr ? mr->name : "(all)", listener->name, 1);
24488d7f2e76SPhilippe Mathieu-Daudé         }
24498d7f2e76SPhilippe Mathieu-Daudé     }
24508d7f2e76SPhilippe Mathieu-Daudé }
24518d7f2e76SPhilippe Mathieu-Daudé 
memory_region_clear_dirty_bitmap(MemoryRegion * mr,hwaddr start,hwaddr len)24528d7f2e76SPhilippe Mathieu-Daudé void memory_region_clear_dirty_bitmap(MemoryRegion *mr, hwaddr start,
24538d7f2e76SPhilippe Mathieu-Daudé                                       hwaddr len)
24548d7f2e76SPhilippe Mathieu-Daudé {
24558d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionSection mrs;
24568d7f2e76SPhilippe Mathieu-Daudé     MemoryListener *listener;
24578d7f2e76SPhilippe Mathieu-Daudé     AddressSpace *as;
24588d7f2e76SPhilippe Mathieu-Daudé     FlatView *view;
24598d7f2e76SPhilippe Mathieu-Daudé     FlatRange *fr;
24608d7f2e76SPhilippe Mathieu-Daudé     hwaddr sec_start, sec_end, sec_size;
24618d7f2e76SPhilippe Mathieu-Daudé 
24628d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(listener, &memory_listeners, link) {
24638d7f2e76SPhilippe Mathieu-Daudé         if (!listener->log_clear) {
24648d7f2e76SPhilippe Mathieu-Daudé             continue;
24658d7f2e76SPhilippe Mathieu-Daudé         }
24668d7f2e76SPhilippe Mathieu-Daudé         as = listener->address_space;
24678d7f2e76SPhilippe Mathieu-Daudé         view = address_space_get_flatview(as);
24688d7f2e76SPhilippe Mathieu-Daudé         FOR_EACH_FLAT_RANGE(fr, view) {
24698d7f2e76SPhilippe Mathieu-Daudé             if (!fr->dirty_log_mask || fr->mr != mr) {
24708d7f2e76SPhilippe Mathieu-Daudé                 /*
24718d7f2e76SPhilippe Mathieu-Daudé                  * Clear dirty bitmap operation only applies to those
24728d7f2e76SPhilippe Mathieu-Daudé                  * regions whose dirty logging is at least enabled
24738d7f2e76SPhilippe Mathieu-Daudé                  */
24748d7f2e76SPhilippe Mathieu-Daudé                 continue;
24758d7f2e76SPhilippe Mathieu-Daudé             }
24768d7f2e76SPhilippe Mathieu-Daudé 
24778d7f2e76SPhilippe Mathieu-Daudé             mrs = section_from_flat_range(fr, view);
24788d7f2e76SPhilippe Mathieu-Daudé 
24798d7f2e76SPhilippe Mathieu-Daudé             sec_start = MAX(mrs.offset_within_region, start);
24808d7f2e76SPhilippe Mathieu-Daudé             sec_end = mrs.offset_within_region + int128_get64(mrs.size);
24818d7f2e76SPhilippe Mathieu-Daudé             sec_end = MIN(sec_end, start + len);
24828d7f2e76SPhilippe Mathieu-Daudé 
24838d7f2e76SPhilippe Mathieu-Daudé             if (sec_start >= sec_end) {
24848d7f2e76SPhilippe Mathieu-Daudé                 /*
24858d7f2e76SPhilippe Mathieu-Daudé                  * If this memory region section has no intersection
24868d7f2e76SPhilippe Mathieu-Daudé                  * with the requested range, skip.
24878d7f2e76SPhilippe Mathieu-Daudé                  */
24888d7f2e76SPhilippe Mathieu-Daudé                 continue;
24898d7f2e76SPhilippe Mathieu-Daudé             }
24908d7f2e76SPhilippe Mathieu-Daudé 
24918d7f2e76SPhilippe Mathieu-Daudé             /* Valid case; shrink the section if needed */
24928d7f2e76SPhilippe Mathieu-Daudé             mrs.offset_within_address_space +=
24938d7f2e76SPhilippe Mathieu-Daudé                 sec_start - mrs.offset_within_region;
24948d7f2e76SPhilippe Mathieu-Daudé             mrs.offset_within_region = sec_start;
24958d7f2e76SPhilippe Mathieu-Daudé             sec_size = sec_end - sec_start;
24968d7f2e76SPhilippe Mathieu-Daudé             mrs.size = int128_make64(sec_size);
24978d7f2e76SPhilippe Mathieu-Daudé             listener->log_clear(listener, &mrs);
24988d7f2e76SPhilippe Mathieu-Daudé         }
24998d7f2e76SPhilippe Mathieu-Daudé         flatview_unref(view);
25008d7f2e76SPhilippe Mathieu-Daudé     }
25018d7f2e76SPhilippe Mathieu-Daudé }
25028d7f2e76SPhilippe Mathieu-Daudé 
memory_region_snapshot_and_clear_dirty(MemoryRegion * mr,hwaddr addr,hwaddr size,unsigned client)25038d7f2e76SPhilippe Mathieu-Daudé DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr,
25048d7f2e76SPhilippe Mathieu-Daudé                                                             hwaddr addr,
25058d7f2e76SPhilippe Mathieu-Daudé                                                             hwaddr size,
25068d7f2e76SPhilippe Mathieu-Daudé                                                             unsigned client)
25078d7f2e76SPhilippe Mathieu-Daudé {
25088d7f2e76SPhilippe Mathieu-Daudé     DirtyBitmapSnapshot *snapshot;
25098d7f2e76SPhilippe Mathieu-Daudé     assert(mr->ram_block);
25108d7f2e76SPhilippe Mathieu-Daudé     memory_region_sync_dirty_bitmap(mr, false);
25118d7f2e76SPhilippe Mathieu-Daudé     snapshot = cpu_physical_memory_snapshot_and_clear_dirty(mr, addr, size, client);
25128d7f2e76SPhilippe Mathieu-Daudé     memory_global_after_dirty_log_sync();
25138d7f2e76SPhilippe Mathieu-Daudé     return snapshot;
25148d7f2e76SPhilippe Mathieu-Daudé }
25158d7f2e76SPhilippe Mathieu-Daudé 
memory_region_snapshot_get_dirty(MemoryRegion * mr,DirtyBitmapSnapshot * snap,hwaddr addr,hwaddr size)25168d7f2e76SPhilippe Mathieu-Daudé bool memory_region_snapshot_get_dirty(MemoryRegion *mr, DirtyBitmapSnapshot *snap,
25178d7f2e76SPhilippe Mathieu-Daudé                                       hwaddr addr, hwaddr size)
25188d7f2e76SPhilippe Mathieu-Daudé {
25198d7f2e76SPhilippe Mathieu-Daudé     assert(mr->ram_block);
25208d7f2e76SPhilippe Mathieu-Daudé     return cpu_physical_memory_snapshot_get_dirty(snap,
25218d7f2e76SPhilippe Mathieu-Daudé                 memory_region_get_ram_addr(mr) + addr, size);
25228d7f2e76SPhilippe Mathieu-Daudé }
25238d7f2e76SPhilippe Mathieu-Daudé 
memory_region_set_readonly(MemoryRegion * mr,bool readonly)25248d7f2e76SPhilippe Mathieu-Daudé void memory_region_set_readonly(MemoryRegion *mr, bool readonly)
25258d7f2e76SPhilippe Mathieu-Daudé {
25268d7f2e76SPhilippe Mathieu-Daudé     if (mr->readonly != readonly) {
25278d7f2e76SPhilippe Mathieu-Daudé         memory_region_transaction_begin();
25288d7f2e76SPhilippe Mathieu-Daudé         mr->readonly = readonly;
25298d7f2e76SPhilippe Mathieu-Daudé         memory_region_update_pending |= mr->enabled;
25308d7f2e76SPhilippe Mathieu-Daudé         memory_region_transaction_commit();
25318d7f2e76SPhilippe Mathieu-Daudé     }
25328d7f2e76SPhilippe Mathieu-Daudé }
25338d7f2e76SPhilippe Mathieu-Daudé 
memory_region_set_nonvolatile(MemoryRegion * mr,bool nonvolatile)25348d7f2e76SPhilippe Mathieu-Daudé void memory_region_set_nonvolatile(MemoryRegion *mr, bool nonvolatile)
25358d7f2e76SPhilippe Mathieu-Daudé {
25368d7f2e76SPhilippe Mathieu-Daudé     if (mr->nonvolatile != nonvolatile) {
25378d7f2e76SPhilippe Mathieu-Daudé         memory_region_transaction_begin();
25388d7f2e76SPhilippe Mathieu-Daudé         mr->nonvolatile = nonvolatile;
25398d7f2e76SPhilippe Mathieu-Daudé         memory_region_update_pending |= mr->enabled;
25408d7f2e76SPhilippe Mathieu-Daudé         memory_region_transaction_commit();
25418d7f2e76SPhilippe Mathieu-Daudé     }
25428d7f2e76SPhilippe Mathieu-Daudé }
25438d7f2e76SPhilippe Mathieu-Daudé 
memory_region_rom_device_set_romd(MemoryRegion * mr,bool romd_mode)25448d7f2e76SPhilippe Mathieu-Daudé void memory_region_rom_device_set_romd(MemoryRegion *mr, bool romd_mode)
25458d7f2e76SPhilippe Mathieu-Daudé {
25468d7f2e76SPhilippe Mathieu-Daudé     if (mr->romd_mode != romd_mode) {
25478d7f2e76SPhilippe Mathieu-Daudé         memory_region_transaction_begin();
25488d7f2e76SPhilippe Mathieu-Daudé         mr->romd_mode = romd_mode;
25498d7f2e76SPhilippe Mathieu-Daudé         memory_region_update_pending |= mr->enabled;
25508d7f2e76SPhilippe Mathieu-Daudé         memory_region_transaction_commit();
25518d7f2e76SPhilippe Mathieu-Daudé     }
25528d7f2e76SPhilippe Mathieu-Daudé }
25538d7f2e76SPhilippe Mathieu-Daudé 
memory_region_reset_dirty(MemoryRegion * mr,hwaddr addr,hwaddr size,unsigned client)25548d7f2e76SPhilippe Mathieu-Daudé void memory_region_reset_dirty(MemoryRegion *mr, hwaddr addr,
25558d7f2e76SPhilippe Mathieu-Daudé                                hwaddr size, unsigned client)
25568d7f2e76SPhilippe Mathieu-Daudé {
25578d7f2e76SPhilippe Mathieu-Daudé     assert(mr->ram_block);
25588d7f2e76SPhilippe Mathieu-Daudé     cpu_physical_memory_test_and_clear_dirty(
25598d7f2e76SPhilippe Mathieu-Daudé         memory_region_get_ram_addr(mr) + addr, size, client);
25608d7f2e76SPhilippe Mathieu-Daudé }
25618d7f2e76SPhilippe Mathieu-Daudé 
memory_region_get_fd(MemoryRegion * mr)25628d7f2e76SPhilippe Mathieu-Daudé int memory_region_get_fd(MemoryRegion *mr)
25638d7f2e76SPhilippe Mathieu-Daudé {
25648d7f2e76SPhilippe Mathieu-Daudé     RCU_READ_LOCK_GUARD();
25658d7f2e76SPhilippe Mathieu-Daudé     while (mr->alias) {
25668d7f2e76SPhilippe Mathieu-Daudé         mr = mr->alias;
25678d7f2e76SPhilippe Mathieu-Daudé     }
25688d7f2e76SPhilippe Mathieu-Daudé     return mr->ram_block->fd;
25698d7f2e76SPhilippe Mathieu-Daudé }
25708d7f2e76SPhilippe Mathieu-Daudé 
memory_region_get_ram_ptr(MemoryRegion * mr)25718d7f2e76SPhilippe Mathieu-Daudé void *memory_region_get_ram_ptr(MemoryRegion *mr)
25728d7f2e76SPhilippe Mathieu-Daudé {
25738d7f2e76SPhilippe Mathieu-Daudé     uint64_t offset = 0;
25748d7f2e76SPhilippe Mathieu-Daudé 
25758d7f2e76SPhilippe Mathieu-Daudé     RCU_READ_LOCK_GUARD();
25768d7f2e76SPhilippe Mathieu-Daudé     while (mr->alias) {
25778d7f2e76SPhilippe Mathieu-Daudé         offset += mr->alias_offset;
25788d7f2e76SPhilippe Mathieu-Daudé         mr = mr->alias;
25798d7f2e76SPhilippe Mathieu-Daudé     }
25808d7f2e76SPhilippe Mathieu-Daudé     assert(mr->ram_block);
25818d7f2e76SPhilippe Mathieu-Daudé     return qemu_map_ram_ptr(mr->ram_block, offset);
25828d7f2e76SPhilippe Mathieu-Daudé }
25838d7f2e76SPhilippe Mathieu-Daudé 
memory_region_from_host(void * ptr,ram_addr_t * offset)25848d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *memory_region_from_host(void *ptr, ram_addr_t *offset)
25858d7f2e76SPhilippe Mathieu-Daudé {
25868d7f2e76SPhilippe Mathieu-Daudé     RAMBlock *block;
25878d7f2e76SPhilippe Mathieu-Daudé 
25888d7f2e76SPhilippe Mathieu-Daudé     block = qemu_ram_block_from_host(ptr, false, offset);
25898d7f2e76SPhilippe Mathieu-Daudé     if (!block) {
25908d7f2e76SPhilippe Mathieu-Daudé         return NULL;
25918d7f2e76SPhilippe Mathieu-Daudé     }
25928d7f2e76SPhilippe Mathieu-Daudé 
25938d7f2e76SPhilippe Mathieu-Daudé     return block->mr;
25948d7f2e76SPhilippe Mathieu-Daudé }
25958d7f2e76SPhilippe Mathieu-Daudé 
memory_region_get_ram_addr(MemoryRegion * mr)25968d7f2e76SPhilippe Mathieu-Daudé ram_addr_t memory_region_get_ram_addr(MemoryRegion *mr)
25978d7f2e76SPhilippe Mathieu-Daudé {
25988d7f2e76SPhilippe Mathieu-Daudé     return mr->ram_block ? mr->ram_block->offset : RAM_ADDR_INVALID;
25998d7f2e76SPhilippe Mathieu-Daudé }
26008d7f2e76SPhilippe Mathieu-Daudé 
memory_region_ram_resize(MemoryRegion * mr,ram_addr_t newsize,Error ** errp)26018d7f2e76SPhilippe Mathieu-Daudé void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp)
26028d7f2e76SPhilippe Mathieu-Daudé {
26038d7f2e76SPhilippe Mathieu-Daudé     assert(mr->ram_block);
26048d7f2e76SPhilippe Mathieu-Daudé 
26058d7f2e76SPhilippe Mathieu-Daudé     qemu_ram_resize(mr->ram_block, newsize, errp);
26068d7f2e76SPhilippe Mathieu-Daudé }
26078d7f2e76SPhilippe Mathieu-Daudé 
memory_region_msync(MemoryRegion * mr,hwaddr addr,hwaddr size)26088d7f2e76SPhilippe Mathieu-Daudé void memory_region_msync(MemoryRegion *mr, hwaddr addr, hwaddr size)
26098d7f2e76SPhilippe Mathieu-Daudé {
26108d7f2e76SPhilippe Mathieu-Daudé     if (mr->ram_block) {
26118d7f2e76SPhilippe Mathieu-Daudé         qemu_ram_msync(mr->ram_block, addr, size);
26128d7f2e76SPhilippe Mathieu-Daudé     }
26138d7f2e76SPhilippe Mathieu-Daudé }
26148d7f2e76SPhilippe Mathieu-Daudé 
memory_region_writeback(MemoryRegion * mr,hwaddr addr,hwaddr size)26158d7f2e76SPhilippe Mathieu-Daudé void memory_region_writeback(MemoryRegion *mr, hwaddr addr, hwaddr size)
26168d7f2e76SPhilippe Mathieu-Daudé {
26178d7f2e76SPhilippe Mathieu-Daudé     /*
26188d7f2e76SPhilippe Mathieu-Daudé      * Might be extended case needed to cover
26198d7f2e76SPhilippe Mathieu-Daudé      * different types of memory regions
26208d7f2e76SPhilippe Mathieu-Daudé      */
26218d7f2e76SPhilippe Mathieu-Daudé     if (mr->dirty_log_mask) {
26228d7f2e76SPhilippe Mathieu-Daudé         memory_region_msync(mr, addr, size);
26238d7f2e76SPhilippe Mathieu-Daudé     }
26248d7f2e76SPhilippe Mathieu-Daudé }
26258d7f2e76SPhilippe Mathieu-Daudé 
26268d7f2e76SPhilippe Mathieu-Daudé /*
26278d7f2e76SPhilippe Mathieu-Daudé  * Call proper memory listeners about the change on the newly
26288d7f2e76SPhilippe Mathieu-Daudé  * added/removed CoalescedMemoryRange.
26298d7f2e76SPhilippe Mathieu-Daudé  */
memory_region_update_coalesced_range(MemoryRegion * mr,CoalescedMemoryRange * cmr,bool add)26308d7f2e76SPhilippe Mathieu-Daudé static void memory_region_update_coalesced_range(MemoryRegion *mr,
26318d7f2e76SPhilippe Mathieu-Daudé                                                  CoalescedMemoryRange *cmr,
26328d7f2e76SPhilippe Mathieu-Daudé                                                  bool add)
26338d7f2e76SPhilippe Mathieu-Daudé {
26348d7f2e76SPhilippe Mathieu-Daudé     AddressSpace *as;
26358d7f2e76SPhilippe Mathieu-Daudé     FlatView *view;
26368d7f2e76SPhilippe Mathieu-Daudé     FlatRange *fr;
26378d7f2e76SPhilippe Mathieu-Daudé 
26388d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
26398d7f2e76SPhilippe Mathieu-Daudé         view = address_space_get_flatview(as);
26408d7f2e76SPhilippe Mathieu-Daudé         FOR_EACH_FLAT_RANGE(fr, view) {
26418d7f2e76SPhilippe Mathieu-Daudé             if (fr->mr == mr) {
26428d7f2e76SPhilippe Mathieu-Daudé                 flat_range_coalesced_io_notify(fr, as, cmr, add);
26438d7f2e76SPhilippe Mathieu-Daudé             }
26448d7f2e76SPhilippe Mathieu-Daudé         }
26458d7f2e76SPhilippe Mathieu-Daudé         flatview_unref(view);
26468d7f2e76SPhilippe Mathieu-Daudé     }
26478d7f2e76SPhilippe Mathieu-Daudé }
26488d7f2e76SPhilippe Mathieu-Daudé 
memory_region_set_coalescing(MemoryRegion * mr)26498d7f2e76SPhilippe Mathieu-Daudé void memory_region_set_coalescing(MemoryRegion *mr)
26508d7f2e76SPhilippe Mathieu-Daudé {
26518d7f2e76SPhilippe Mathieu-Daudé     memory_region_clear_coalescing(mr);
26528d7f2e76SPhilippe Mathieu-Daudé     memory_region_add_coalescing(mr, 0, int128_get64(mr->size));
26538d7f2e76SPhilippe Mathieu-Daudé }
26548d7f2e76SPhilippe Mathieu-Daudé 
memory_region_add_coalescing(MemoryRegion * mr,hwaddr offset,uint64_t size)26558d7f2e76SPhilippe Mathieu-Daudé void memory_region_add_coalescing(MemoryRegion *mr,
26568d7f2e76SPhilippe Mathieu-Daudé                                   hwaddr offset,
26578d7f2e76SPhilippe Mathieu-Daudé                                   uint64_t size)
26588d7f2e76SPhilippe Mathieu-Daudé {
26598d7f2e76SPhilippe Mathieu-Daudé     CoalescedMemoryRange *cmr = g_malloc(sizeof(*cmr));
26608d7f2e76SPhilippe Mathieu-Daudé 
26618d7f2e76SPhilippe Mathieu-Daudé     cmr->addr = addrrange_make(int128_make64(offset), int128_make64(size));
26628d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_INSERT_TAIL(&mr->coalesced, cmr, link);
26638d7f2e76SPhilippe Mathieu-Daudé     memory_region_update_coalesced_range(mr, cmr, true);
26648d7f2e76SPhilippe Mathieu-Daudé     memory_region_set_flush_coalesced(mr);
26658d7f2e76SPhilippe Mathieu-Daudé }
26668d7f2e76SPhilippe Mathieu-Daudé 
memory_region_clear_coalescing(MemoryRegion * mr)26678d7f2e76SPhilippe Mathieu-Daudé void memory_region_clear_coalescing(MemoryRegion *mr)
26688d7f2e76SPhilippe Mathieu-Daudé {
26698d7f2e76SPhilippe Mathieu-Daudé     CoalescedMemoryRange *cmr;
26708d7f2e76SPhilippe Mathieu-Daudé 
26718d7f2e76SPhilippe Mathieu-Daudé     if (QTAILQ_EMPTY(&mr->coalesced)) {
26728d7f2e76SPhilippe Mathieu-Daudé         return;
26738d7f2e76SPhilippe Mathieu-Daudé     }
26748d7f2e76SPhilippe Mathieu-Daudé 
26758d7f2e76SPhilippe Mathieu-Daudé     qemu_flush_coalesced_mmio_buffer();
26768d7f2e76SPhilippe Mathieu-Daudé     mr->flush_coalesced_mmio = false;
26778d7f2e76SPhilippe Mathieu-Daudé 
26788d7f2e76SPhilippe Mathieu-Daudé     while (!QTAILQ_EMPTY(&mr->coalesced)) {
26798d7f2e76SPhilippe Mathieu-Daudé         cmr = QTAILQ_FIRST(&mr->coalesced);
26808d7f2e76SPhilippe Mathieu-Daudé         QTAILQ_REMOVE(&mr->coalesced, cmr, link);
26818d7f2e76SPhilippe Mathieu-Daudé         memory_region_update_coalesced_range(mr, cmr, false);
26828d7f2e76SPhilippe Mathieu-Daudé         g_free(cmr);
26838d7f2e76SPhilippe Mathieu-Daudé     }
26848d7f2e76SPhilippe Mathieu-Daudé }
26858d7f2e76SPhilippe Mathieu-Daudé 
memory_region_set_flush_coalesced(MemoryRegion * mr)26868d7f2e76SPhilippe Mathieu-Daudé void memory_region_set_flush_coalesced(MemoryRegion *mr)
26878d7f2e76SPhilippe Mathieu-Daudé {
26888d7f2e76SPhilippe Mathieu-Daudé     mr->flush_coalesced_mmio = true;
26898d7f2e76SPhilippe Mathieu-Daudé }
26908d7f2e76SPhilippe Mathieu-Daudé 
memory_region_clear_flush_coalesced(MemoryRegion * mr)26918d7f2e76SPhilippe Mathieu-Daudé void memory_region_clear_flush_coalesced(MemoryRegion *mr)
26928d7f2e76SPhilippe Mathieu-Daudé {
26938d7f2e76SPhilippe Mathieu-Daudé     qemu_flush_coalesced_mmio_buffer();
26948d7f2e76SPhilippe Mathieu-Daudé     if (QTAILQ_EMPTY(&mr->coalesced)) {
26958d7f2e76SPhilippe Mathieu-Daudé         mr->flush_coalesced_mmio = false;
26968d7f2e76SPhilippe Mathieu-Daudé     }
26978d7f2e76SPhilippe Mathieu-Daudé }
26988d7f2e76SPhilippe Mathieu-Daudé 
memory_region_add_eventfd(MemoryRegion * mr,hwaddr addr,unsigned size,bool match_data,uint64_t data,EventNotifier * e)26998d7f2e76SPhilippe Mathieu-Daudé void memory_region_add_eventfd(MemoryRegion *mr,
27008d7f2e76SPhilippe Mathieu-Daudé                                hwaddr addr,
27018d7f2e76SPhilippe Mathieu-Daudé                                unsigned size,
27028d7f2e76SPhilippe Mathieu-Daudé                                bool match_data,
27038d7f2e76SPhilippe Mathieu-Daudé                                uint64_t data,
27048d7f2e76SPhilippe Mathieu-Daudé                                EventNotifier *e)
27058d7f2e76SPhilippe Mathieu-Daudé {
27068d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionIoeventfd mrfd = {
27078d7f2e76SPhilippe Mathieu-Daudé         .addr.start = int128_make64(addr),
27088d7f2e76SPhilippe Mathieu-Daudé         .addr.size = int128_make64(size),
27098d7f2e76SPhilippe Mathieu-Daudé         .match_data = match_data,
27108d7f2e76SPhilippe Mathieu-Daudé         .data = data,
27118d7f2e76SPhilippe Mathieu-Daudé         .e = e,
27128d7f2e76SPhilippe Mathieu-Daudé     };
27138d7f2e76SPhilippe Mathieu-Daudé     unsigned i;
27148d7f2e76SPhilippe Mathieu-Daudé 
27158d7f2e76SPhilippe Mathieu-Daudé     if (size) {
27168d7f2e76SPhilippe Mathieu-Daudé         adjust_endianness(mr, &mrfd.data, size_memop(size) | MO_TE);
27178d7f2e76SPhilippe Mathieu-Daudé     }
27188d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_begin();
27198d7f2e76SPhilippe Mathieu-Daudé     for (i = 0; i < mr->ioeventfd_nb; ++i) {
27208d7f2e76SPhilippe Mathieu-Daudé         if (memory_region_ioeventfd_before(&mrfd, &mr->ioeventfds[i])) {
27218d7f2e76SPhilippe Mathieu-Daudé             break;
27228d7f2e76SPhilippe Mathieu-Daudé         }
27238d7f2e76SPhilippe Mathieu-Daudé     }
27248d7f2e76SPhilippe Mathieu-Daudé     ++mr->ioeventfd_nb;
27258d7f2e76SPhilippe Mathieu-Daudé     mr->ioeventfds = g_realloc(mr->ioeventfds,
27268d7f2e76SPhilippe Mathieu-Daudé                                   sizeof(*mr->ioeventfds) * mr->ioeventfd_nb);
27278d7f2e76SPhilippe Mathieu-Daudé     memmove(&mr->ioeventfds[i+1], &mr->ioeventfds[i],
27288d7f2e76SPhilippe Mathieu-Daudé             sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb-1 - i));
27298d7f2e76SPhilippe Mathieu-Daudé     mr->ioeventfds[i] = mrfd;
27308d7f2e76SPhilippe Mathieu-Daudé     ioeventfd_update_pending |= mr->enabled;
27318d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_commit();
27328d7f2e76SPhilippe Mathieu-Daudé }
27338d7f2e76SPhilippe Mathieu-Daudé 
memory_region_del_eventfd(MemoryRegion * mr,hwaddr addr,unsigned size,bool match_data,uint64_t data,EventNotifier * e)27348d7f2e76SPhilippe Mathieu-Daudé void memory_region_del_eventfd(MemoryRegion *mr,
27358d7f2e76SPhilippe Mathieu-Daudé                                hwaddr addr,
27368d7f2e76SPhilippe Mathieu-Daudé                                unsigned size,
27378d7f2e76SPhilippe Mathieu-Daudé                                bool match_data,
27388d7f2e76SPhilippe Mathieu-Daudé                                uint64_t data,
27398d7f2e76SPhilippe Mathieu-Daudé                                EventNotifier *e)
27408d7f2e76SPhilippe Mathieu-Daudé {
27418d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionIoeventfd mrfd = {
27428d7f2e76SPhilippe Mathieu-Daudé         .addr.start = int128_make64(addr),
27438d7f2e76SPhilippe Mathieu-Daudé         .addr.size = int128_make64(size),
27448d7f2e76SPhilippe Mathieu-Daudé         .match_data = match_data,
27458d7f2e76SPhilippe Mathieu-Daudé         .data = data,
27468d7f2e76SPhilippe Mathieu-Daudé         .e = e,
27478d7f2e76SPhilippe Mathieu-Daudé     };
27488d7f2e76SPhilippe Mathieu-Daudé     unsigned i;
27498d7f2e76SPhilippe Mathieu-Daudé 
27508d7f2e76SPhilippe Mathieu-Daudé     if (size) {
27518d7f2e76SPhilippe Mathieu-Daudé         adjust_endianness(mr, &mrfd.data, size_memop(size) | MO_TE);
27528d7f2e76SPhilippe Mathieu-Daudé     }
27538d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_begin();
27548d7f2e76SPhilippe Mathieu-Daudé     for (i = 0; i < mr->ioeventfd_nb; ++i) {
27558d7f2e76SPhilippe Mathieu-Daudé         if (memory_region_ioeventfd_equal(&mrfd, &mr->ioeventfds[i])) {
27568d7f2e76SPhilippe Mathieu-Daudé             break;
27578d7f2e76SPhilippe Mathieu-Daudé         }
27588d7f2e76SPhilippe Mathieu-Daudé     }
27598d7f2e76SPhilippe Mathieu-Daudé     assert(i != mr->ioeventfd_nb);
27608d7f2e76SPhilippe Mathieu-Daudé     memmove(&mr->ioeventfds[i], &mr->ioeventfds[i+1],
27618d7f2e76SPhilippe Mathieu-Daudé             sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb - (i+1)));
27628d7f2e76SPhilippe Mathieu-Daudé     --mr->ioeventfd_nb;
27638d7f2e76SPhilippe Mathieu-Daudé     mr->ioeventfds = g_realloc(mr->ioeventfds,
27648d7f2e76SPhilippe Mathieu-Daudé                                   sizeof(*mr->ioeventfds)*mr->ioeventfd_nb + 1);
27658d7f2e76SPhilippe Mathieu-Daudé     ioeventfd_update_pending |= mr->enabled;
27668d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_commit();
27678d7f2e76SPhilippe Mathieu-Daudé }
27688d7f2e76SPhilippe Mathieu-Daudé 
memory_region_update_container_subregions(MemoryRegion * subregion)27698d7f2e76SPhilippe Mathieu-Daudé static void memory_region_update_container_subregions(MemoryRegion *subregion)
27708d7f2e76SPhilippe Mathieu-Daudé {
27718d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr = subregion->container;
27728d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *other;
27738d7f2e76SPhilippe Mathieu-Daudé 
27748d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_begin();
27758d7f2e76SPhilippe Mathieu-Daudé 
27768d7f2e76SPhilippe Mathieu-Daudé     memory_region_ref(subregion);
27778d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(other, &mr->subregions, subregions_link) {
27788d7f2e76SPhilippe Mathieu-Daudé         if (subregion->priority >= other->priority) {
27798d7f2e76SPhilippe Mathieu-Daudé             QTAILQ_INSERT_BEFORE(other, subregion, subregions_link);
27808d7f2e76SPhilippe Mathieu-Daudé             goto done;
27818d7f2e76SPhilippe Mathieu-Daudé         }
27828d7f2e76SPhilippe Mathieu-Daudé     }
27838d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_INSERT_TAIL(&mr->subregions, subregion, subregions_link);
27848d7f2e76SPhilippe Mathieu-Daudé done:
27858d7f2e76SPhilippe Mathieu-Daudé     memory_region_update_pending |= mr->enabled && subregion->enabled;
27868d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_commit();
27878d7f2e76SPhilippe Mathieu-Daudé }
27888d7f2e76SPhilippe Mathieu-Daudé 
memory_region_add_subregion_common(MemoryRegion * mr,hwaddr offset,MemoryRegion * subregion)27898d7f2e76SPhilippe Mathieu-Daudé static void memory_region_add_subregion_common(MemoryRegion *mr,
27908d7f2e76SPhilippe Mathieu-Daudé                                                hwaddr offset,
27918d7f2e76SPhilippe Mathieu-Daudé                                                MemoryRegion *subregion)
27928d7f2e76SPhilippe Mathieu-Daudé {
27938d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *alias;
27948d7f2e76SPhilippe Mathieu-Daudé 
27958d7f2e76SPhilippe Mathieu-Daudé     assert(!subregion->container);
27968d7f2e76SPhilippe Mathieu-Daudé     subregion->container = mr;
27978d7f2e76SPhilippe Mathieu-Daudé     for (alias = subregion->alias; alias; alias = alias->alias) {
27988d7f2e76SPhilippe Mathieu-Daudé         alias->mapped_via_alias++;
27998d7f2e76SPhilippe Mathieu-Daudé     }
28008d7f2e76SPhilippe Mathieu-Daudé     subregion->addr = offset;
28018d7f2e76SPhilippe Mathieu-Daudé     memory_region_update_container_subregions(subregion);
28028d7f2e76SPhilippe Mathieu-Daudé }
28038d7f2e76SPhilippe Mathieu-Daudé 
memory_region_add_subregion(MemoryRegion * mr,hwaddr offset,MemoryRegion * subregion)28048d7f2e76SPhilippe Mathieu-Daudé void memory_region_add_subregion(MemoryRegion *mr,
28058d7f2e76SPhilippe Mathieu-Daudé                                  hwaddr offset,
28068d7f2e76SPhilippe Mathieu-Daudé                                  MemoryRegion *subregion)
28078d7f2e76SPhilippe Mathieu-Daudé {
28088d7f2e76SPhilippe Mathieu-Daudé     subregion->priority = 0;
28098d7f2e76SPhilippe Mathieu-Daudé     memory_region_add_subregion_common(mr, offset, subregion);
28108d7f2e76SPhilippe Mathieu-Daudé }
28118d7f2e76SPhilippe Mathieu-Daudé 
memory_region_add_subregion_overlap(MemoryRegion * mr,hwaddr offset,MemoryRegion * subregion,int priority)28128d7f2e76SPhilippe Mathieu-Daudé void memory_region_add_subregion_overlap(MemoryRegion *mr,
28138d7f2e76SPhilippe Mathieu-Daudé                                          hwaddr offset,
28148d7f2e76SPhilippe Mathieu-Daudé                                          MemoryRegion *subregion,
28158d7f2e76SPhilippe Mathieu-Daudé                                          int priority)
28168d7f2e76SPhilippe Mathieu-Daudé {
28178d7f2e76SPhilippe Mathieu-Daudé     subregion->priority = priority;
28188d7f2e76SPhilippe Mathieu-Daudé     memory_region_add_subregion_common(mr, offset, subregion);
28198d7f2e76SPhilippe Mathieu-Daudé }
28208d7f2e76SPhilippe Mathieu-Daudé 
memory_region_del_subregion(MemoryRegion * mr,MemoryRegion * subregion)28218d7f2e76SPhilippe Mathieu-Daudé void memory_region_del_subregion(MemoryRegion *mr,
28228d7f2e76SPhilippe Mathieu-Daudé                                  MemoryRegion *subregion)
28238d7f2e76SPhilippe Mathieu-Daudé {
28248d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *alias;
28258d7f2e76SPhilippe Mathieu-Daudé 
28268d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_begin();
28278d7f2e76SPhilippe Mathieu-Daudé     assert(subregion->container == mr);
28288d7f2e76SPhilippe Mathieu-Daudé     subregion->container = NULL;
28298d7f2e76SPhilippe Mathieu-Daudé     for (alias = subregion->alias; alias; alias = alias->alias) {
28308d7f2e76SPhilippe Mathieu-Daudé         alias->mapped_via_alias--;
28318d7f2e76SPhilippe Mathieu-Daudé         assert(alias->mapped_via_alias >= 0);
28328d7f2e76SPhilippe Mathieu-Daudé     }
28338d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link);
28348d7f2e76SPhilippe Mathieu-Daudé     memory_region_unref(subregion);
28358d7f2e76SPhilippe Mathieu-Daudé     memory_region_update_pending |= mr->enabled && subregion->enabled;
28368d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_commit();
28378d7f2e76SPhilippe Mathieu-Daudé }
28388d7f2e76SPhilippe Mathieu-Daudé 
memory_region_set_enabled(MemoryRegion * mr,bool enabled)28398d7f2e76SPhilippe Mathieu-Daudé void memory_region_set_enabled(MemoryRegion *mr, bool enabled)
28408d7f2e76SPhilippe Mathieu-Daudé {
28418d7f2e76SPhilippe Mathieu-Daudé     if (enabled == mr->enabled) {
28428d7f2e76SPhilippe Mathieu-Daudé         return;
28438d7f2e76SPhilippe Mathieu-Daudé     }
28448d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_begin();
28458d7f2e76SPhilippe Mathieu-Daudé     mr->enabled = enabled;
28468d7f2e76SPhilippe Mathieu-Daudé     memory_region_update_pending = true;
28478d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_commit();
28488d7f2e76SPhilippe Mathieu-Daudé }
28498d7f2e76SPhilippe Mathieu-Daudé 
memory_region_set_size(MemoryRegion * mr,uint64_t size)28508d7f2e76SPhilippe Mathieu-Daudé void memory_region_set_size(MemoryRegion *mr, uint64_t size)
28518d7f2e76SPhilippe Mathieu-Daudé {
28528d7f2e76SPhilippe Mathieu-Daudé     Int128 s = int128_make64(size);
28538d7f2e76SPhilippe Mathieu-Daudé 
28548d7f2e76SPhilippe Mathieu-Daudé     if (size == UINT64_MAX) {
28558d7f2e76SPhilippe Mathieu-Daudé         s = int128_2_64();
28568d7f2e76SPhilippe Mathieu-Daudé     }
28578d7f2e76SPhilippe Mathieu-Daudé     if (int128_eq(s, mr->size)) {
28588d7f2e76SPhilippe Mathieu-Daudé         return;
28598d7f2e76SPhilippe Mathieu-Daudé     }
28608d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_begin();
28618d7f2e76SPhilippe Mathieu-Daudé     mr->size = s;
28628d7f2e76SPhilippe Mathieu-Daudé     memory_region_update_pending = true;
28638d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_commit();
28648d7f2e76SPhilippe Mathieu-Daudé }
28658d7f2e76SPhilippe Mathieu-Daudé 
memory_region_readd_subregion(MemoryRegion * mr)28668d7f2e76SPhilippe Mathieu-Daudé static void memory_region_readd_subregion(MemoryRegion *mr)
28678d7f2e76SPhilippe Mathieu-Daudé {
28688d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *container = mr->container;
28698d7f2e76SPhilippe Mathieu-Daudé 
28708d7f2e76SPhilippe Mathieu-Daudé     if (container) {
28718d7f2e76SPhilippe Mathieu-Daudé         memory_region_transaction_begin();
28728d7f2e76SPhilippe Mathieu-Daudé         memory_region_ref(mr);
28738d7f2e76SPhilippe Mathieu-Daudé         memory_region_del_subregion(container, mr);
28748d7f2e76SPhilippe Mathieu-Daudé         memory_region_add_subregion_common(container, mr->addr, mr);
28758d7f2e76SPhilippe Mathieu-Daudé         memory_region_unref(mr);
28768d7f2e76SPhilippe Mathieu-Daudé         memory_region_transaction_commit();
28778d7f2e76SPhilippe Mathieu-Daudé     }
28788d7f2e76SPhilippe Mathieu-Daudé }
28798d7f2e76SPhilippe Mathieu-Daudé 
memory_region_set_address(MemoryRegion * mr,hwaddr addr)28808d7f2e76SPhilippe Mathieu-Daudé void memory_region_set_address(MemoryRegion *mr, hwaddr addr)
28818d7f2e76SPhilippe Mathieu-Daudé {
28828d7f2e76SPhilippe Mathieu-Daudé     if (addr != mr->addr) {
28838d7f2e76SPhilippe Mathieu-Daudé         mr->addr = addr;
28848d7f2e76SPhilippe Mathieu-Daudé         memory_region_readd_subregion(mr);
28858d7f2e76SPhilippe Mathieu-Daudé     }
28868d7f2e76SPhilippe Mathieu-Daudé }
28878d7f2e76SPhilippe Mathieu-Daudé 
memory_region_set_alias_offset(MemoryRegion * mr,hwaddr offset)28888d7f2e76SPhilippe Mathieu-Daudé void memory_region_set_alias_offset(MemoryRegion *mr, hwaddr offset)
28898d7f2e76SPhilippe Mathieu-Daudé {
28908d7f2e76SPhilippe Mathieu-Daudé     assert(mr->alias);
28918d7f2e76SPhilippe Mathieu-Daudé 
28928d7f2e76SPhilippe Mathieu-Daudé     if (offset == mr->alias_offset) {
28938d7f2e76SPhilippe Mathieu-Daudé         return;
28948d7f2e76SPhilippe Mathieu-Daudé     }
28958d7f2e76SPhilippe Mathieu-Daudé 
28968d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_begin();
28978d7f2e76SPhilippe Mathieu-Daudé     mr->alias_offset = offset;
28988d7f2e76SPhilippe Mathieu-Daudé     memory_region_update_pending |= mr->enabled;
28998d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_commit();
29008d7f2e76SPhilippe Mathieu-Daudé }
29018d7f2e76SPhilippe Mathieu-Daudé 
memory_region_set_unmergeable(MemoryRegion * mr,bool unmergeable)2902533f5d66SDavid Hildenbrand void memory_region_set_unmergeable(MemoryRegion *mr, bool unmergeable)
2903533f5d66SDavid Hildenbrand {
2904533f5d66SDavid Hildenbrand     if (unmergeable == mr->unmergeable) {
2905533f5d66SDavid Hildenbrand         return;
2906533f5d66SDavid Hildenbrand     }
2907533f5d66SDavid Hildenbrand 
2908533f5d66SDavid Hildenbrand     memory_region_transaction_begin();
2909533f5d66SDavid Hildenbrand     mr->unmergeable = unmergeable;
2910533f5d66SDavid Hildenbrand     memory_region_update_pending |= mr->enabled;
2911533f5d66SDavid Hildenbrand     memory_region_transaction_commit();
2912533f5d66SDavid Hildenbrand }
2913533f5d66SDavid Hildenbrand 
memory_region_get_alignment(const MemoryRegion * mr)29148d7f2e76SPhilippe Mathieu-Daudé uint64_t memory_region_get_alignment(const MemoryRegion *mr)
29158d7f2e76SPhilippe Mathieu-Daudé {
29168d7f2e76SPhilippe Mathieu-Daudé     return mr->align;
29178d7f2e76SPhilippe Mathieu-Daudé }
29188d7f2e76SPhilippe Mathieu-Daudé 
cmp_flatrange_addr(const void * addr_,const void * fr_)29198d7f2e76SPhilippe Mathieu-Daudé static int cmp_flatrange_addr(const void *addr_, const void *fr_)
29208d7f2e76SPhilippe Mathieu-Daudé {
29218d7f2e76SPhilippe Mathieu-Daudé     const AddrRange *addr = addr_;
29228d7f2e76SPhilippe Mathieu-Daudé     const FlatRange *fr = fr_;
29238d7f2e76SPhilippe Mathieu-Daudé 
29248d7f2e76SPhilippe Mathieu-Daudé     if (int128_le(addrrange_end(*addr), fr->addr.start)) {
29258d7f2e76SPhilippe Mathieu-Daudé         return -1;
29268d7f2e76SPhilippe Mathieu-Daudé     } else if (int128_ge(addr->start, addrrange_end(fr->addr))) {
29278d7f2e76SPhilippe Mathieu-Daudé         return 1;
29288d7f2e76SPhilippe Mathieu-Daudé     }
29298d7f2e76SPhilippe Mathieu-Daudé     return 0;
29308d7f2e76SPhilippe Mathieu-Daudé }
29318d7f2e76SPhilippe Mathieu-Daudé 
flatview_lookup(FlatView * view,AddrRange addr)29328d7f2e76SPhilippe Mathieu-Daudé static FlatRange *flatview_lookup(FlatView *view, AddrRange addr)
29338d7f2e76SPhilippe Mathieu-Daudé {
29348d7f2e76SPhilippe Mathieu-Daudé     return bsearch(&addr, view->ranges, view->nr,
29358d7f2e76SPhilippe Mathieu-Daudé                    sizeof(FlatRange), cmp_flatrange_addr);
29368d7f2e76SPhilippe Mathieu-Daudé }
29378d7f2e76SPhilippe Mathieu-Daudé 
memory_region_is_mapped(MemoryRegion * mr)29388d7f2e76SPhilippe Mathieu-Daudé bool memory_region_is_mapped(MemoryRegion *mr)
29398d7f2e76SPhilippe Mathieu-Daudé {
29408d7f2e76SPhilippe Mathieu-Daudé     return !!mr->container || mr->mapped_via_alias;
29418d7f2e76SPhilippe Mathieu-Daudé }
29428d7f2e76SPhilippe Mathieu-Daudé 
29438d7f2e76SPhilippe Mathieu-Daudé /* Same as memory_region_find, but it does not add a reference to the
29448d7f2e76SPhilippe Mathieu-Daudé  * returned region.  It must be called from an RCU critical section.
29458d7f2e76SPhilippe Mathieu-Daudé  */
memory_region_find_rcu(MemoryRegion * mr,hwaddr addr,uint64_t size)29468d7f2e76SPhilippe Mathieu-Daudé static MemoryRegionSection memory_region_find_rcu(MemoryRegion *mr,
29478d7f2e76SPhilippe Mathieu-Daudé                                                   hwaddr addr, uint64_t size)
29488d7f2e76SPhilippe Mathieu-Daudé {
29498d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionSection ret = { .mr = NULL };
29508d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *root;
29518d7f2e76SPhilippe Mathieu-Daudé     AddressSpace *as;
29528d7f2e76SPhilippe Mathieu-Daudé     AddrRange range;
29538d7f2e76SPhilippe Mathieu-Daudé     FlatView *view;
29548d7f2e76SPhilippe Mathieu-Daudé     FlatRange *fr;
29558d7f2e76SPhilippe Mathieu-Daudé 
29568d7f2e76SPhilippe Mathieu-Daudé     addr += mr->addr;
29578d7f2e76SPhilippe Mathieu-Daudé     for (root = mr; root->container; ) {
29588d7f2e76SPhilippe Mathieu-Daudé         root = root->container;
29598d7f2e76SPhilippe Mathieu-Daudé         addr += root->addr;
29608d7f2e76SPhilippe Mathieu-Daudé     }
29618d7f2e76SPhilippe Mathieu-Daudé 
29628d7f2e76SPhilippe Mathieu-Daudé     as = memory_region_to_address_space(root);
29638d7f2e76SPhilippe Mathieu-Daudé     if (!as) {
29648d7f2e76SPhilippe Mathieu-Daudé         return ret;
29658d7f2e76SPhilippe Mathieu-Daudé     }
29668d7f2e76SPhilippe Mathieu-Daudé     range = addrrange_make(int128_make64(addr), int128_make64(size));
29678d7f2e76SPhilippe Mathieu-Daudé 
29688d7f2e76SPhilippe Mathieu-Daudé     view = address_space_to_flatview(as);
29698d7f2e76SPhilippe Mathieu-Daudé     fr = flatview_lookup(view, range);
29708d7f2e76SPhilippe Mathieu-Daudé     if (!fr) {
29718d7f2e76SPhilippe Mathieu-Daudé         return ret;
29728d7f2e76SPhilippe Mathieu-Daudé     }
29738d7f2e76SPhilippe Mathieu-Daudé 
29748d7f2e76SPhilippe Mathieu-Daudé     while (fr > view->ranges && addrrange_intersects(fr[-1].addr, range)) {
29758d7f2e76SPhilippe Mathieu-Daudé         --fr;
29768d7f2e76SPhilippe Mathieu-Daudé     }
29778d7f2e76SPhilippe Mathieu-Daudé 
29788d7f2e76SPhilippe Mathieu-Daudé     ret.mr = fr->mr;
29798d7f2e76SPhilippe Mathieu-Daudé     ret.fv = view;
29808d7f2e76SPhilippe Mathieu-Daudé     range = addrrange_intersection(range, fr->addr);
29818d7f2e76SPhilippe Mathieu-Daudé     ret.offset_within_region = fr->offset_in_region;
29828d7f2e76SPhilippe Mathieu-Daudé     ret.offset_within_region += int128_get64(int128_sub(range.start,
29838d7f2e76SPhilippe Mathieu-Daudé                                                         fr->addr.start));
29848d7f2e76SPhilippe Mathieu-Daudé     ret.size = range.size;
29858d7f2e76SPhilippe Mathieu-Daudé     ret.offset_within_address_space = int128_get64(range.start);
29868d7f2e76SPhilippe Mathieu-Daudé     ret.readonly = fr->readonly;
29878d7f2e76SPhilippe Mathieu-Daudé     ret.nonvolatile = fr->nonvolatile;
29888d7f2e76SPhilippe Mathieu-Daudé     return ret;
29898d7f2e76SPhilippe Mathieu-Daudé }
29908d7f2e76SPhilippe Mathieu-Daudé 
memory_region_find(MemoryRegion * mr,hwaddr addr,uint64_t size)29918d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection memory_region_find(MemoryRegion *mr,
29928d7f2e76SPhilippe Mathieu-Daudé                                        hwaddr addr, uint64_t size)
29938d7f2e76SPhilippe Mathieu-Daudé {
29948d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionSection ret;
29958d7f2e76SPhilippe Mathieu-Daudé     RCU_READ_LOCK_GUARD();
29968d7f2e76SPhilippe Mathieu-Daudé     ret = memory_region_find_rcu(mr, addr, size);
29978d7f2e76SPhilippe Mathieu-Daudé     if (ret.mr) {
29988d7f2e76SPhilippe Mathieu-Daudé         memory_region_ref(ret.mr);
29998d7f2e76SPhilippe Mathieu-Daudé     }
30008d7f2e76SPhilippe Mathieu-Daudé     return ret;
30018d7f2e76SPhilippe Mathieu-Daudé }
30028d7f2e76SPhilippe Mathieu-Daudé 
memory_region_section_new_copy(MemoryRegionSection * s)30038d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *memory_region_section_new_copy(MemoryRegionSection *s)
30048d7f2e76SPhilippe Mathieu-Daudé {
30058d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionSection *tmp = g_new(MemoryRegionSection, 1);
30068d7f2e76SPhilippe Mathieu-Daudé 
30078d7f2e76SPhilippe Mathieu-Daudé     *tmp = *s;
30088d7f2e76SPhilippe Mathieu-Daudé     if (tmp->mr) {
30098d7f2e76SPhilippe Mathieu-Daudé         memory_region_ref(tmp->mr);
30108d7f2e76SPhilippe Mathieu-Daudé     }
30118d7f2e76SPhilippe Mathieu-Daudé     if (tmp->fv) {
30128d7f2e76SPhilippe Mathieu-Daudé         bool ret  = flatview_ref(tmp->fv);
30138d7f2e76SPhilippe Mathieu-Daudé 
30148d7f2e76SPhilippe Mathieu-Daudé         g_assert(ret);
30158d7f2e76SPhilippe Mathieu-Daudé     }
30168d7f2e76SPhilippe Mathieu-Daudé     return tmp;
30178d7f2e76SPhilippe Mathieu-Daudé }
30188d7f2e76SPhilippe Mathieu-Daudé 
memory_region_section_free_copy(MemoryRegionSection * s)30198d7f2e76SPhilippe Mathieu-Daudé void memory_region_section_free_copy(MemoryRegionSection *s)
30208d7f2e76SPhilippe Mathieu-Daudé {
30218d7f2e76SPhilippe Mathieu-Daudé     if (s->fv) {
30228d7f2e76SPhilippe Mathieu-Daudé         flatview_unref(s->fv);
30238d7f2e76SPhilippe Mathieu-Daudé     }
30248d7f2e76SPhilippe Mathieu-Daudé     if (s->mr) {
30258d7f2e76SPhilippe Mathieu-Daudé         memory_region_unref(s->mr);
30268d7f2e76SPhilippe Mathieu-Daudé     }
30278d7f2e76SPhilippe Mathieu-Daudé     g_free(s);
30288d7f2e76SPhilippe Mathieu-Daudé }
30298d7f2e76SPhilippe Mathieu-Daudé 
memory_region_present(MemoryRegion * container,hwaddr addr)30308d7f2e76SPhilippe Mathieu-Daudé bool memory_region_present(MemoryRegion *container, hwaddr addr)
30318d7f2e76SPhilippe Mathieu-Daudé {
30328d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr;
30338d7f2e76SPhilippe Mathieu-Daudé 
30348d7f2e76SPhilippe Mathieu-Daudé     RCU_READ_LOCK_GUARD();
30358d7f2e76SPhilippe Mathieu-Daudé     mr = memory_region_find_rcu(container, addr, 1).mr;
30368d7f2e76SPhilippe Mathieu-Daudé     return mr && mr != container;
30378d7f2e76SPhilippe Mathieu-Daudé }
30388d7f2e76SPhilippe Mathieu-Daudé 
memory_global_dirty_log_sync(bool last_stage)30398d7f2e76SPhilippe Mathieu-Daudé void memory_global_dirty_log_sync(bool last_stage)
30408d7f2e76SPhilippe Mathieu-Daudé {
30418d7f2e76SPhilippe Mathieu-Daudé     memory_region_sync_dirty_bitmap(NULL, last_stage);
30428d7f2e76SPhilippe Mathieu-Daudé }
30438d7f2e76SPhilippe Mathieu-Daudé 
memory_global_after_dirty_log_sync(void)30448d7f2e76SPhilippe Mathieu-Daudé void memory_global_after_dirty_log_sync(void)
30458d7f2e76SPhilippe Mathieu-Daudé {
30468d7f2e76SPhilippe Mathieu-Daudé     MEMORY_LISTENER_CALL_GLOBAL(log_global_after_sync, Forward);
30478d7f2e76SPhilippe Mathieu-Daudé }
30488d7f2e76SPhilippe Mathieu-Daudé 
30498d7f2e76SPhilippe Mathieu-Daudé /*
30508d7f2e76SPhilippe Mathieu-Daudé  * Dirty track stop flags that are postponed due to VM being stopped.  Should
30518d7f2e76SPhilippe Mathieu-Daudé  * only be used within vmstate_change hook.
30528d7f2e76SPhilippe Mathieu-Daudé  */
30538d7f2e76SPhilippe Mathieu-Daudé static unsigned int postponed_stop_flags;
30548d7f2e76SPhilippe Mathieu-Daudé static VMChangeStateEntry *vmstate_change;
30558d7f2e76SPhilippe Mathieu-Daudé static void memory_global_dirty_log_stop_postponed_run(void);
30568d7f2e76SPhilippe Mathieu-Daudé 
memory_global_dirty_log_do_start(Error ** errp)30573688fec8SCédric Le Goater static bool memory_global_dirty_log_do_start(Error **errp)
30583688fec8SCédric Le Goater {
30593688fec8SCédric Le Goater     MemoryListener *listener;
30603688fec8SCédric Le Goater 
30613688fec8SCédric Le Goater     QTAILQ_FOREACH(listener, &memory_listeners, link) {
30623688fec8SCédric Le Goater         if (listener->log_global_start) {
30633688fec8SCédric Le Goater             if (!listener->log_global_start(listener, errp)) {
30643688fec8SCédric Le Goater                 goto err;
30653688fec8SCédric Le Goater             }
30663688fec8SCédric Le Goater         }
30673688fec8SCédric Le Goater     }
30683688fec8SCédric Le Goater     return true;
30693688fec8SCédric Le Goater 
30703688fec8SCédric Le Goater err:
30713688fec8SCédric Le Goater     while ((listener = QTAILQ_PREV(listener, link)) != NULL) {
30723688fec8SCédric Le Goater         if (listener->log_global_stop) {
30733688fec8SCédric Le Goater             listener->log_global_stop(listener);
30743688fec8SCédric Le Goater         }
30753688fec8SCédric Le Goater     }
30763688fec8SCédric Le Goater 
30773688fec8SCédric Le Goater     return false;
30783688fec8SCédric Le Goater }
30793688fec8SCédric Le Goater 
memory_global_dirty_log_start(unsigned int flags,Error ** errp)3080639ec3fbSCédric Le Goater bool memory_global_dirty_log_start(unsigned int flags, Error **errp)
30818d7f2e76SPhilippe Mathieu-Daudé {
30828d7f2e76SPhilippe Mathieu-Daudé     unsigned int old_flags;
30838d7f2e76SPhilippe Mathieu-Daudé 
30848d7f2e76SPhilippe Mathieu-Daudé     assert(flags && !(flags & (~GLOBAL_DIRTY_MASK)));
30858d7f2e76SPhilippe Mathieu-Daudé 
30868d7f2e76SPhilippe Mathieu-Daudé     if (vmstate_change) {
30878d7f2e76SPhilippe Mathieu-Daudé         /* If there is postponed stop(), operate on it first */
30888d7f2e76SPhilippe Mathieu-Daudé         postponed_stop_flags &= ~flags;
30898d7f2e76SPhilippe Mathieu-Daudé         memory_global_dirty_log_stop_postponed_run();
30908d7f2e76SPhilippe Mathieu-Daudé     }
30918d7f2e76SPhilippe Mathieu-Daudé 
30928d7f2e76SPhilippe Mathieu-Daudé     flags &= ~global_dirty_tracking;
30938d7f2e76SPhilippe Mathieu-Daudé     if (!flags) {
3094639ec3fbSCédric Le Goater         return true;
30958d7f2e76SPhilippe Mathieu-Daudé     }
30968d7f2e76SPhilippe Mathieu-Daudé 
30978d7f2e76SPhilippe Mathieu-Daudé     old_flags = global_dirty_tracking;
30988d7f2e76SPhilippe Mathieu-Daudé     global_dirty_tracking |= flags;
30998d7f2e76SPhilippe Mathieu-Daudé     trace_global_dirty_changed(global_dirty_tracking);
31008d7f2e76SPhilippe Mathieu-Daudé 
31018d7f2e76SPhilippe Mathieu-Daudé     if (!old_flags) {
3102639ec3fbSCédric Le Goater         if (!memory_global_dirty_log_do_start(errp)) {
31033688fec8SCédric Le Goater             global_dirty_tracking &= ~flags;
31043688fec8SCédric Le Goater             trace_global_dirty_changed(global_dirty_tracking);
3105639ec3fbSCédric Le Goater             return false;
31063688fec8SCédric Le Goater         }
31073688fec8SCédric Le Goater 
31088d7f2e76SPhilippe Mathieu-Daudé         memory_region_transaction_begin();
31098d7f2e76SPhilippe Mathieu-Daudé         memory_region_update_pending = true;
31108d7f2e76SPhilippe Mathieu-Daudé         memory_region_transaction_commit();
31118d7f2e76SPhilippe Mathieu-Daudé     }
3112639ec3fbSCédric Le Goater     return true;
31138d7f2e76SPhilippe Mathieu-Daudé }
31148d7f2e76SPhilippe Mathieu-Daudé 
memory_global_dirty_log_do_stop(unsigned int flags)31158d7f2e76SPhilippe Mathieu-Daudé static void memory_global_dirty_log_do_stop(unsigned int flags)
31168d7f2e76SPhilippe Mathieu-Daudé {
31178d7f2e76SPhilippe Mathieu-Daudé     assert(flags && !(flags & (~GLOBAL_DIRTY_MASK)));
31188d7f2e76SPhilippe Mathieu-Daudé     assert((global_dirty_tracking & flags) == flags);
31198d7f2e76SPhilippe Mathieu-Daudé     global_dirty_tracking &= ~flags;
31208d7f2e76SPhilippe Mathieu-Daudé 
31218d7f2e76SPhilippe Mathieu-Daudé     trace_global_dirty_changed(global_dirty_tracking);
31228d7f2e76SPhilippe Mathieu-Daudé 
31238d7f2e76SPhilippe Mathieu-Daudé     if (!global_dirty_tracking) {
31248d7f2e76SPhilippe Mathieu-Daudé         memory_region_transaction_begin();
31258d7f2e76SPhilippe Mathieu-Daudé         memory_region_update_pending = true;
31268d7f2e76SPhilippe Mathieu-Daudé         memory_region_transaction_commit();
31278d7f2e76SPhilippe Mathieu-Daudé         MEMORY_LISTENER_CALL_GLOBAL(log_global_stop, Reverse);
31288d7f2e76SPhilippe Mathieu-Daudé     }
31298d7f2e76SPhilippe Mathieu-Daudé }
31308d7f2e76SPhilippe Mathieu-Daudé 
31318d7f2e76SPhilippe Mathieu-Daudé /*
31328d7f2e76SPhilippe Mathieu-Daudé  * Execute the postponed dirty log stop operations if there is, then reset
31338d7f2e76SPhilippe Mathieu-Daudé  * everything (including the flags and the vmstate change hook).
31348d7f2e76SPhilippe Mathieu-Daudé  */
memory_global_dirty_log_stop_postponed_run(void)31358d7f2e76SPhilippe Mathieu-Daudé static void memory_global_dirty_log_stop_postponed_run(void)
31368d7f2e76SPhilippe Mathieu-Daudé {
31378d7f2e76SPhilippe Mathieu-Daudé     /* This must be called with the vmstate handler registered */
31388d7f2e76SPhilippe Mathieu-Daudé     assert(vmstate_change);
31398d7f2e76SPhilippe Mathieu-Daudé 
31408d7f2e76SPhilippe Mathieu-Daudé     /* Note: postponed_stop_flags can be cleared in log start routine */
31418d7f2e76SPhilippe Mathieu-Daudé     if (postponed_stop_flags) {
31428d7f2e76SPhilippe Mathieu-Daudé         memory_global_dirty_log_do_stop(postponed_stop_flags);
31438d7f2e76SPhilippe Mathieu-Daudé         postponed_stop_flags = 0;
31448d7f2e76SPhilippe Mathieu-Daudé     }
31458d7f2e76SPhilippe Mathieu-Daudé 
31468d7f2e76SPhilippe Mathieu-Daudé     qemu_del_vm_change_state_handler(vmstate_change);
31478d7f2e76SPhilippe Mathieu-Daudé     vmstate_change = NULL;
31488d7f2e76SPhilippe Mathieu-Daudé }
31498d7f2e76SPhilippe Mathieu-Daudé 
memory_vm_change_state_handler(void * opaque,bool running,RunState state)31508d7f2e76SPhilippe Mathieu-Daudé static void memory_vm_change_state_handler(void *opaque, bool running,
31518d7f2e76SPhilippe Mathieu-Daudé                                            RunState state)
31528d7f2e76SPhilippe Mathieu-Daudé {
31538d7f2e76SPhilippe Mathieu-Daudé     if (running) {
31548d7f2e76SPhilippe Mathieu-Daudé         memory_global_dirty_log_stop_postponed_run();
31558d7f2e76SPhilippe Mathieu-Daudé     }
31568d7f2e76SPhilippe Mathieu-Daudé }
31578d7f2e76SPhilippe Mathieu-Daudé 
memory_global_dirty_log_stop(unsigned int flags)31588d7f2e76SPhilippe Mathieu-Daudé void memory_global_dirty_log_stop(unsigned int flags)
31598d7f2e76SPhilippe Mathieu-Daudé {
31608d7f2e76SPhilippe Mathieu-Daudé     if (!runstate_is_running()) {
31618d7f2e76SPhilippe Mathieu-Daudé         /* Postpone the dirty log stop, e.g., to when VM starts again */
31628d7f2e76SPhilippe Mathieu-Daudé         if (vmstate_change) {
31638d7f2e76SPhilippe Mathieu-Daudé             /* Batch with previous postponed flags */
31648d7f2e76SPhilippe Mathieu-Daudé             postponed_stop_flags |= flags;
31658d7f2e76SPhilippe Mathieu-Daudé         } else {
31668d7f2e76SPhilippe Mathieu-Daudé             postponed_stop_flags = flags;
31678d7f2e76SPhilippe Mathieu-Daudé             vmstate_change = qemu_add_vm_change_state_handler(
31688d7f2e76SPhilippe Mathieu-Daudé                 memory_vm_change_state_handler, NULL);
31698d7f2e76SPhilippe Mathieu-Daudé         }
31708d7f2e76SPhilippe Mathieu-Daudé         return;
31718d7f2e76SPhilippe Mathieu-Daudé     }
31728d7f2e76SPhilippe Mathieu-Daudé 
31738d7f2e76SPhilippe Mathieu-Daudé     memory_global_dirty_log_do_stop(flags);
31748d7f2e76SPhilippe Mathieu-Daudé }
31758d7f2e76SPhilippe Mathieu-Daudé 
listener_add_address_space(MemoryListener * listener,AddressSpace * as)31768d7f2e76SPhilippe Mathieu-Daudé static void listener_add_address_space(MemoryListener *listener,
31778d7f2e76SPhilippe Mathieu-Daudé                                        AddressSpace *as)
31788d7f2e76SPhilippe Mathieu-Daudé {
31798d3031faSAni Sinha     unsigned i;
31808d7f2e76SPhilippe Mathieu-Daudé     FlatView *view;
31818d7f2e76SPhilippe Mathieu-Daudé     FlatRange *fr;
31828d3031faSAni Sinha     MemoryRegionIoeventfd *fd;
31838d7f2e76SPhilippe Mathieu-Daudé 
31848d7f2e76SPhilippe Mathieu-Daudé     if (listener->begin) {
31858d7f2e76SPhilippe Mathieu-Daudé         listener->begin(listener);
31868d7f2e76SPhilippe Mathieu-Daudé     }
31878d7f2e76SPhilippe Mathieu-Daudé     if (global_dirty_tracking) {
31883688fec8SCédric Le Goater         /*
31893688fec8SCédric Le Goater          * Currently only VFIO can fail log_global_start(), and it's not
31903688fec8SCédric Le Goater          * yet allowed to hotplug any PCI device during migration. So this
31913688fec8SCédric Le Goater          * should never fail when invoked, guard it with error_abort.  If
31923688fec8SCédric Le Goater          * it can start to fail in the future, we need to be able to fail
31933688fec8SCédric Le Goater          * the whole listener_add_address_space() and its callers.
31943688fec8SCédric Le Goater          */
31958d7f2e76SPhilippe Mathieu-Daudé         if (listener->log_global_start) {
31963688fec8SCédric Le Goater             listener->log_global_start(listener, &error_abort);
31978d7f2e76SPhilippe Mathieu-Daudé         }
31988d7f2e76SPhilippe Mathieu-Daudé     }
31998d7f2e76SPhilippe Mathieu-Daudé 
32008d7f2e76SPhilippe Mathieu-Daudé     view = address_space_get_flatview(as);
32018d7f2e76SPhilippe Mathieu-Daudé     FOR_EACH_FLAT_RANGE(fr, view) {
32028d7f2e76SPhilippe Mathieu-Daudé         MemoryRegionSection section = section_from_flat_range(fr, view);
32038d7f2e76SPhilippe Mathieu-Daudé 
32048d7f2e76SPhilippe Mathieu-Daudé         if (listener->region_add) {
32058d7f2e76SPhilippe Mathieu-Daudé             listener->region_add(listener, &section);
32068d7f2e76SPhilippe Mathieu-Daudé         }
32078d3031faSAni Sinha 
32088d3031faSAni Sinha         /* send coalesced io add notifications */
32098d3031faSAni Sinha         flat_range_coalesced_io_notify_listener_add_del(fr, &section,
32108d3031faSAni Sinha                                                         listener, as, true);
32118d3031faSAni Sinha 
32128d7f2e76SPhilippe Mathieu-Daudé         if (fr->dirty_log_mask && listener->log_start) {
32138d7f2e76SPhilippe Mathieu-Daudé             listener->log_start(listener, &section, 0, fr->dirty_log_mask);
32148d7f2e76SPhilippe Mathieu-Daudé         }
32158d7f2e76SPhilippe Mathieu-Daudé     }
32168d3031faSAni Sinha 
32178d3031faSAni Sinha     /*
32188d3031faSAni Sinha      * register all eventfds for this address space for the newly registered
32198d3031faSAni Sinha      * listener.
32208d3031faSAni Sinha      */
32218d3031faSAni Sinha     for (i = 0; i < as->ioeventfd_nb; i++) {
32228d3031faSAni Sinha         fd = &as->ioeventfds[i];
32238d3031faSAni Sinha         MemoryRegionSection section = (MemoryRegionSection) {
32248d3031faSAni Sinha             .fv = view,
32258d3031faSAni Sinha             .offset_within_address_space = int128_get64(fd->addr.start),
32268d3031faSAni Sinha             .size = fd->addr.size,
32278d3031faSAni Sinha         };
32288d3031faSAni Sinha 
32298d3031faSAni Sinha         if (listener->eventfd_add) {
32308d3031faSAni Sinha             listener->eventfd_add(listener, &section,
32318d3031faSAni Sinha                                   fd->match_data, fd->data, fd->e);
32328d3031faSAni Sinha         }
32338d3031faSAni Sinha     }
32348d3031faSAni Sinha 
32358d7f2e76SPhilippe Mathieu-Daudé     if (listener->commit) {
32368d7f2e76SPhilippe Mathieu-Daudé         listener->commit(listener);
32378d7f2e76SPhilippe Mathieu-Daudé     }
32388d7f2e76SPhilippe Mathieu-Daudé     flatview_unref(view);
32398d7f2e76SPhilippe Mathieu-Daudé }
32408d7f2e76SPhilippe Mathieu-Daudé 
listener_del_address_space(MemoryListener * listener,AddressSpace * as)32418d7f2e76SPhilippe Mathieu-Daudé static void listener_del_address_space(MemoryListener *listener,
32428d7f2e76SPhilippe Mathieu-Daudé                                        AddressSpace *as)
32438d7f2e76SPhilippe Mathieu-Daudé {
32448d3031faSAni Sinha     unsigned i;
32458d7f2e76SPhilippe Mathieu-Daudé     FlatView *view;
32468d7f2e76SPhilippe Mathieu-Daudé     FlatRange *fr;
32478d3031faSAni Sinha     MemoryRegionIoeventfd *fd;
32488d7f2e76SPhilippe Mathieu-Daudé 
32498d7f2e76SPhilippe Mathieu-Daudé     if (listener->begin) {
32508d7f2e76SPhilippe Mathieu-Daudé         listener->begin(listener);
32518d7f2e76SPhilippe Mathieu-Daudé     }
32528d7f2e76SPhilippe Mathieu-Daudé     view = address_space_get_flatview(as);
32538d7f2e76SPhilippe Mathieu-Daudé     FOR_EACH_FLAT_RANGE(fr, view) {
32548d7f2e76SPhilippe Mathieu-Daudé         MemoryRegionSection section = section_from_flat_range(fr, view);
32558d7f2e76SPhilippe Mathieu-Daudé 
32568d7f2e76SPhilippe Mathieu-Daudé         if (fr->dirty_log_mask && listener->log_stop) {
32578d7f2e76SPhilippe Mathieu-Daudé             listener->log_stop(listener, &section, fr->dirty_log_mask, 0);
32588d7f2e76SPhilippe Mathieu-Daudé         }
32598d3031faSAni Sinha 
32608d3031faSAni Sinha         /* send coalesced io del notifications */
32618d3031faSAni Sinha         flat_range_coalesced_io_notify_listener_add_del(fr, &section,
32628d3031faSAni Sinha                                                         listener, as, false);
32638d7f2e76SPhilippe Mathieu-Daudé         if (listener->region_del) {
32648d7f2e76SPhilippe Mathieu-Daudé             listener->region_del(listener, &section);
32658d7f2e76SPhilippe Mathieu-Daudé         }
32668d7f2e76SPhilippe Mathieu-Daudé     }
32678d3031faSAni Sinha 
32688d3031faSAni Sinha     /*
32698d3031faSAni Sinha      * de-register all eventfds for this address space for the current
32708d3031faSAni Sinha      * listener.
32718d3031faSAni Sinha      */
32728d3031faSAni Sinha     for (i = 0; i < as->ioeventfd_nb; i++) {
32738d3031faSAni Sinha         fd = &as->ioeventfds[i];
32748d3031faSAni Sinha         MemoryRegionSection section = (MemoryRegionSection) {
32758d3031faSAni Sinha             .fv = view,
32768d3031faSAni Sinha             .offset_within_address_space = int128_get64(fd->addr.start),
32778d3031faSAni Sinha             .size = fd->addr.size,
32788d3031faSAni Sinha         };
32798d3031faSAni Sinha 
32808d3031faSAni Sinha         if (listener->eventfd_del) {
32818d3031faSAni Sinha             listener->eventfd_del(listener, &section,
32828d3031faSAni Sinha                                   fd->match_data, fd->data, fd->e);
32838d3031faSAni Sinha         }
32848d3031faSAni Sinha     }
32858d3031faSAni Sinha 
32868d7f2e76SPhilippe Mathieu-Daudé     if (listener->commit) {
32878d7f2e76SPhilippe Mathieu-Daudé         listener->commit(listener);
32888d7f2e76SPhilippe Mathieu-Daudé     }
32898d7f2e76SPhilippe Mathieu-Daudé     flatview_unref(view);
32908d7f2e76SPhilippe Mathieu-Daudé }
32918d7f2e76SPhilippe Mathieu-Daudé 
memory_listener_register(MemoryListener * listener,AddressSpace * as)32928d7f2e76SPhilippe Mathieu-Daudé void memory_listener_register(MemoryListener *listener, AddressSpace *as)
32938d7f2e76SPhilippe Mathieu-Daudé {
32948d7f2e76SPhilippe Mathieu-Daudé     MemoryListener *other = NULL;
32958d7f2e76SPhilippe Mathieu-Daudé 
32968d7f2e76SPhilippe Mathieu-Daudé     /* Only one of them can be defined for a listener */
32978d7f2e76SPhilippe Mathieu-Daudé     assert(!(listener->log_sync && listener->log_sync_global));
32988d7f2e76SPhilippe Mathieu-Daudé 
32998d7f2e76SPhilippe Mathieu-Daudé     listener->address_space = as;
33008d7f2e76SPhilippe Mathieu-Daudé     if (QTAILQ_EMPTY(&memory_listeners)
33018d7f2e76SPhilippe Mathieu-Daudé         || listener->priority >= QTAILQ_LAST(&memory_listeners)->priority) {
33028d7f2e76SPhilippe Mathieu-Daudé         QTAILQ_INSERT_TAIL(&memory_listeners, listener, link);
33038d7f2e76SPhilippe Mathieu-Daudé     } else {
33048d7f2e76SPhilippe Mathieu-Daudé         QTAILQ_FOREACH(other, &memory_listeners, link) {
33058d7f2e76SPhilippe Mathieu-Daudé             if (listener->priority < other->priority) {
33068d7f2e76SPhilippe Mathieu-Daudé                 break;
33078d7f2e76SPhilippe Mathieu-Daudé             }
33088d7f2e76SPhilippe Mathieu-Daudé         }
33098d7f2e76SPhilippe Mathieu-Daudé         QTAILQ_INSERT_BEFORE(other, listener, link);
33108d7f2e76SPhilippe Mathieu-Daudé     }
33118d7f2e76SPhilippe Mathieu-Daudé 
33128d7f2e76SPhilippe Mathieu-Daudé     if (QTAILQ_EMPTY(&as->listeners)
33138d7f2e76SPhilippe Mathieu-Daudé         || listener->priority >= QTAILQ_LAST(&as->listeners)->priority) {
33148d7f2e76SPhilippe Mathieu-Daudé         QTAILQ_INSERT_TAIL(&as->listeners, listener, link_as);
33158d7f2e76SPhilippe Mathieu-Daudé     } else {
33168d7f2e76SPhilippe Mathieu-Daudé         QTAILQ_FOREACH(other, &as->listeners, link_as) {
33178d7f2e76SPhilippe Mathieu-Daudé             if (listener->priority < other->priority) {
33188d7f2e76SPhilippe Mathieu-Daudé                 break;
33198d7f2e76SPhilippe Mathieu-Daudé             }
33208d7f2e76SPhilippe Mathieu-Daudé         }
33218d7f2e76SPhilippe Mathieu-Daudé         QTAILQ_INSERT_BEFORE(other, listener, link_as);
33228d7f2e76SPhilippe Mathieu-Daudé     }
33238d7f2e76SPhilippe Mathieu-Daudé 
33248d7f2e76SPhilippe Mathieu-Daudé     listener_add_address_space(listener, as);
33258d7f2e76SPhilippe Mathieu-Daudé 
33268d7f2e76SPhilippe Mathieu-Daudé     if (listener->eventfd_add || listener->eventfd_del) {
33278d7f2e76SPhilippe Mathieu-Daudé         as->ioeventfd_notifiers++;
33288d7f2e76SPhilippe Mathieu-Daudé     }
33298d7f2e76SPhilippe Mathieu-Daudé }
33308d7f2e76SPhilippe Mathieu-Daudé 
memory_listener_unregister(MemoryListener * listener)33318d7f2e76SPhilippe Mathieu-Daudé void memory_listener_unregister(MemoryListener *listener)
33328d7f2e76SPhilippe Mathieu-Daudé {
33338d7f2e76SPhilippe Mathieu-Daudé     if (!listener->address_space) {
33348d7f2e76SPhilippe Mathieu-Daudé         return;
33358d7f2e76SPhilippe Mathieu-Daudé     }
33368d7f2e76SPhilippe Mathieu-Daudé 
33378d7f2e76SPhilippe Mathieu-Daudé     if (listener->eventfd_add || listener->eventfd_del) {
33388d7f2e76SPhilippe Mathieu-Daudé         listener->address_space->ioeventfd_notifiers--;
33398d7f2e76SPhilippe Mathieu-Daudé     }
33408d7f2e76SPhilippe Mathieu-Daudé 
33418d7f2e76SPhilippe Mathieu-Daudé     listener_del_address_space(listener, listener->address_space);
33428d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_REMOVE(&memory_listeners, listener, link);
33438d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_REMOVE(&listener->address_space->listeners, listener, link_as);
33448d7f2e76SPhilippe Mathieu-Daudé     listener->address_space = NULL;
33458d7f2e76SPhilippe Mathieu-Daudé }
33468d7f2e76SPhilippe Mathieu-Daudé 
address_space_remove_listeners(AddressSpace * as)33478d7f2e76SPhilippe Mathieu-Daudé void address_space_remove_listeners(AddressSpace *as)
33488d7f2e76SPhilippe Mathieu-Daudé {
33498d7f2e76SPhilippe Mathieu-Daudé     while (!QTAILQ_EMPTY(&as->listeners)) {
33508d7f2e76SPhilippe Mathieu-Daudé         memory_listener_unregister(QTAILQ_FIRST(&as->listeners));
33518d7f2e76SPhilippe Mathieu-Daudé     }
33528d7f2e76SPhilippe Mathieu-Daudé }
33538d7f2e76SPhilippe Mathieu-Daudé 
address_space_init(AddressSpace * as,MemoryRegion * root,const char * name)33548d7f2e76SPhilippe Mathieu-Daudé void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
33558d7f2e76SPhilippe Mathieu-Daudé {
33568d7f2e76SPhilippe Mathieu-Daudé     memory_region_ref(root);
33578d7f2e76SPhilippe Mathieu-Daudé     as->root = root;
33588d7f2e76SPhilippe Mathieu-Daudé     as->current_map = NULL;
33598d7f2e76SPhilippe Mathieu-Daudé     as->ioeventfd_nb = 0;
33608d7f2e76SPhilippe Mathieu-Daudé     as->ioeventfds = NULL;
33618d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_INIT(&as->listeners);
33628d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
3363637b0aa1SMattias Nissler     as->max_bounce_buffer_size = DEFAULT_MAX_BOUNCE_BUFFER_SIZE;
3364637b0aa1SMattias Nissler     as->bounce_buffer_size = 0;
336569e78f1bSMattias Nissler     qemu_mutex_init(&as->map_client_list_lock);
336669e78f1bSMattias Nissler     QLIST_INIT(&as->map_client_list);
33678d7f2e76SPhilippe Mathieu-Daudé     as->name = g_strdup(name ? name : "anonymous");
33688d7f2e76SPhilippe Mathieu-Daudé     address_space_update_topology(as);
33698d7f2e76SPhilippe Mathieu-Daudé     address_space_update_ioeventfds(as);
33708d7f2e76SPhilippe Mathieu-Daudé }
33718d7f2e76SPhilippe Mathieu-Daudé 
do_address_space_destroy(AddressSpace * as)33728d7f2e76SPhilippe Mathieu-Daudé static void do_address_space_destroy(AddressSpace *as)
33738d7f2e76SPhilippe Mathieu-Daudé {
3374637b0aa1SMattias Nissler     assert(qatomic_read(&as->bounce_buffer_size) == 0);
337569e78f1bSMattias Nissler     assert(QLIST_EMPTY(&as->map_client_list));
337669e78f1bSMattias Nissler     qemu_mutex_destroy(&as->map_client_list_lock);
337769e78f1bSMattias Nissler 
33788d7f2e76SPhilippe Mathieu-Daudé     assert(QTAILQ_EMPTY(&as->listeners));
33798d7f2e76SPhilippe Mathieu-Daudé 
33808d7f2e76SPhilippe Mathieu-Daudé     flatview_unref(as->current_map);
33818d7f2e76SPhilippe Mathieu-Daudé     g_free(as->name);
33828d7f2e76SPhilippe Mathieu-Daudé     g_free(as->ioeventfds);
33838d7f2e76SPhilippe Mathieu-Daudé     memory_region_unref(as->root);
33848d7f2e76SPhilippe Mathieu-Daudé }
33858d7f2e76SPhilippe Mathieu-Daudé 
address_space_destroy(AddressSpace * as)33868d7f2e76SPhilippe Mathieu-Daudé void address_space_destroy(AddressSpace *as)
33878d7f2e76SPhilippe Mathieu-Daudé {
33888d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *root = as->root;
33898d7f2e76SPhilippe Mathieu-Daudé 
33908d7f2e76SPhilippe Mathieu-Daudé     /* Flush out anything from MemoryListeners listening in on this */
33918d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_begin();
33928d7f2e76SPhilippe Mathieu-Daudé     as->root = NULL;
33938d7f2e76SPhilippe Mathieu-Daudé     memory_region_transaction_commit();
33948d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_REMOVE(&address_spaces, as, address_spaces_link);
33958d7f2e76SPhilippe Mathieu-Daudé 
33968d7f2e76SPhilippe Mathieu-Daudé     /* At this point, as->dispatch and as->current_map are dummy
33978d7f2e76SPhilippe Mathieu-Daudé      * entries that the guest should never use.  Wait for the old
33988d7f2e76SPhilippe Mathieu-Daudé      * values to expire before freeing the data.
33998d7f2e76SPhilippe Mathieu-Daudé      */
34008d7f2e76SPhilippe Mathieu-Daudé     as->root = root;
34018d7f2e76SPhilippe Mathieu-Daudé     call_rcu(as, do_address_space_destroy, rcu);
34028d7f2e76SPhilippe Mathieu-Daudé }
34038d7f2e76SPhilippe Mathieu-Daudé 
memory_region_type(MemoryRegion * mr)34048d7f2e76SPhilippe Mathieu-Daudé static const char *memory_region_type(MemoryRegion *mr)
34058d7f2e76SPhilippe Mathieu-Daudé {
34068d7f2e76SPhilippe Mathieu-Daudé     if (mr->alias) {
34078d7f2e76SPhilippe Mathieu-Daudé         return memory_region_type(mr->alias);
34088d7f2e76SPhilippe Mathieu-Daudé     }
34098d7f2e76SPhilippe Mathieu-Daudé     if (memory_region_is_ram_device(mr)) {
34108d7f2e76SPhilippe Mathieu-Daudé         return "ramd";
34118d7f2e76SPhilippe Mathieu-Daudé     } else if (memory_region_is_romd(mr)) {
34128d7f2e76SPhilippe Mathieu-Daudé         return "romd";
34138d7f2e76SPhilippe Mathieu-Daudé     } else if (memory_region_is_rom(mr)) {
34148d7f2e76SPhilippe Mathieu-Daudé         return "rom";
34158d7f2e76SPhilippe Mathieu-Daudé     } else if (memory_region_is_ram(mr)) {
34168d7f2e76SPhilippe Mathieu-Daudé         return "ram";
34178d7f2e76SPhilippe Mathieu-Daudé     } else {
34188d7f2e76SPhilippe Mathieu-Daudé         return "i/o";
34198d7f2e76SPhilippe Mathieu-Daudé     }
34208d7f2e76SPhilippe Mathieu-Daudé }
34218d7f2e76SPhilippe Mathieu-Daudé 
34228d7f2e76SPhilippe Mathieu-Daudé typedef struct MemoryRegionList MemoryRegionList;
34238d7f2e76SPhilippe Mathieu-Daudé 
34248d7f2e76SPhilippe Mathieu-Daudé struct MemoryRegionList {
34258d7f2e76SPhilippe Mathieu-Daudé     const MemoryRegion *mr;
34268d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_ENTRY(MemoryRegionList) mrqueue;
34278d7f2e76SPhilippe Mathieu-Daudé };
34288d7f2e76SPhilippe Mathieu-Daudé 
34298d7f2e76SPhilippe Mathieu-Daudé typedef QTAILQ_HEAD(, MemoryRegionList) MemoryRegionListHead;
34308d7f2e76SPhilippe Mathieu-Daudé 
34318d7f2e76SPhilippe Mathieu-Daudé #define MR_SIZE(size) (int128_nz(size) ? (hwaddr)int128_get64( \
34328d7f2e76SPhilippe Mathieu-Daudé                            int128_sub((size), int128_one())) : 0)
34338d7f2e76SPhilippe Mathieu-Daudé #define MTREE_INDENT "  "
34348d7f2e76SPhilippe Mathieu-Daudé 
mtree_expand_owner(const char * label,Object * obj)34358d7f2e76SPhilippe Mathieu-Daudé static void mtree_expand_owner(const char *label, Object *obj)
34368d7f2e76SPhilippe Mathieu-Daudé {
34378d7f2e76SPhilippe Mathieu-Daudé     DeviceState *dev = (DeviceState *) object_dynamic_cast(obj, TYPE_DEVICE);
34388d7f2e76SPhilippe Mathieu-Daudé 
34398d7f2e76SPhilippe Mathieu-Daudé     qemu_printf(" %s:{%s", label, dev ? "dev" : "obj");
34408d7f2e76SPhilippe Mathieu-Daudé     if (dev && dev->id) {
34418d7f2e76SPhilippe Mathieu-Daudé         qemu_printf(" id=%s", dev->id);
34428d7f2e76SPhilippe Mathieu-Daudé     } else {
34438d7f2e76SPhilippe Mathieu-Daudé         char *canonical_path = object_get_canonical_path(obj);
34448d7f2e76SPhilippe Mathieu-Daudé         if (canonical_path) {
34458d7f2e76SPhilippe Mathieu-Daudé             qemu_printf(" path=%s", canonical_path);
34468d7f2e76SPhilippe Mathieu-Daudé             g_free(canonical_path);
34478d7f2e76SPhilippe Mathieu-Daudé         } else {
34488d7f2e76SPhilippe Mathieu-Daudé             qemu_printf(" type=%s", object_get_typename(obj));
34498d7f2e76SPhilippe Mathieu-Daudé         }
34508d7f2e76SPhilippe Mathieu-Daudé     }
34518d7f2e76SPhilippe Mathieu-Daudé     qemu_printf("}");
34528d7f2e76SPhilippe Mathieu-Daudé }
34538d7f2e76SPhilippe Mathieu-Daudé 
mtree_print_mr_owner(const MemoryRegion * mr)34548d7f2e76SPhilippe Mathieu-Daudé static void mtree_print_mr_owner(const MemoryRegion *mr)
34558d7f2e76SPhilippe Mathieu-Daudé {
34568d7f2e76SPhilippe Mathieu-Daudé     Object *owner = mr->owner;
34578d7f2e76SPhilippe Mathieu-Daudé     Object *parent = memory_region_owner((MemoryRegion *)mr);
34588d7f2e76SPhilippe Mathieu-Daudé 
34598d7f2e76SPhilippe Mathieu-Daudé     if (!owner && !parent) {
34608d7f2e76SPhilippe Mathieu-Daudé         qemu_printf(" orphan");
34618d7f2e76SPhilippe Mathieu-Daudé         return;
34628d7f2e76SPhilippe Mathieu-Daudé     }
34638d7f2e76SPhilippe Mathieu-Daudé     if (owner) {
34648d7f2e76SPhilippe Mathieu-Daudé         mtree_expand_owner("owner", owner);
34658d7f2e76SPhilippe Mathieu-Daudé     }
34668d7f2e76SPhilippe Mathieu-Daudé     if (parent && parent != owner) {
34678d7f2e76SPhilippe Mathieu-Daudé         mtree_expand_owner("parent", parent);
34688d7f2e76SPhilippe Mathieu-Daudé     }
34698d7f2e76SPhilippe Mathieu-Daudé }
34708d7f2e76SPhilippe Mathieu-Daudé 
mtree_print_mr(const MemoryRegion * mr,unsigned int level,hwaddr base,MemoryRegionListHead * alias_print_queue,bool owner,bool display_disabled)34718d7f2e76SPhilippe Mathieu-Daudé static void mtree_print_mr(const MemoryRegion *mr, unsigned int level,
34728d7f2e76SPhilippe Mathieu-Daudé                            hwaddr base,
34738d7f2e76SPhilippe Mathieu-Daudé                            MemoryRegionListHead *alias_print_queue,
34748d7f2e76SPhilippe Mathieu-Daudé                            bool owner, bool display_disabled)
34758d7f2e76SPhilippe Mathieu-Daudé {
34768d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionList *new_ml, *ml, *next_ml;
34778d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionListHead submr_print_queue;
34788d7f2e76SPhilippe Mathieu-Daudé     const MemoryRegion *submr;
34798d7f2e76SPhilippe Mathieu-Daudé     unsigned int i;
34808d7f2e76SPhilippe Mathieu-Daudé     hwaddr cur_start, cur_end;
34818d7f2e76SPhilippe Mathieu-Daudé 
34828d7f2e76SPhilippe Mathieu-Daudé     if (!mr) {
34838d7f2e76SPhilippe Mathieu-Daudé         return;
34848d7f2e76SPhilippe Mathieu-Daudé     }
34858d7f2e76SPhilippe Mathieu-Daudé 
34868d7f2e76SPhilippe Mathieu-Daudé     cur_start = base + mr->addr;
34878d7f2e76SPhilippe Mathieu-Daudé     cur_end = cur_start + MR_SIZE(mr->size);
34888d7f2e76SPhilippe Mathieu-Daudé 
34898d7f2e76SPhilippe Mathieu-Daudé     /*
34908d7f2e76SPhilippe Mathieu-Daudé      * Try to detect overflow of memory region. This should never
34918d7f2e76SPhilippe Mathieu-Daudé      * happen normally. When it happens, we dump something to warn the
34928d7f2e76SPhilippe Mathieu-Daudé      * user who is observing this.
34938d7f2e76SPhilippe Mathieu-Daudé      */
34948d7f2e76SPhilippe Mathieu-Daudé     if (cur_start < base || cur_end < cur_start) {
34958d7f2e76SPhilippe Mathieu-Daudé         qemu_printf("[DETECTED OVERFLOW!] ");
34968d7f2e76SPhilippe Mathieu-Daudé     }
34978d7f2e76SPhilippe Mathieu-Daudé 
34988d7f2e76SPhilippe Mathieu-Daudé     if (mr->alias) {
34998d7f2e76SPhilippe Mathieu-Daudé         bool found = false;
35008d7f2e76SPhilippe Mathieu-Daudé 
35018d7f2e76SPhilippe Mathieu-Daudé         /* check if the alias is already in the queue */
35028d7f2e76SPhilippe Mathieu-Daudé         QTAILQ_FOREACH(ml, alias_print_queue, mrqueue) {
35038d7f2e76SPhilippe Mathieu-Daudé             if (ml->mr == mr->alias) {
35048d7f2e76SPhilippe Mathieu-Daudé                 found = true;
35058d7f2e76SPhilippe Mathieu-Daudé             }
35068d7f2e76SPhilippe Mathieu-Daudé         }
35078d7f2e76SPhilippe Mathieu-Daudé 
35088d7f2e76SPhilippe Mathieu-Daudé         if (!found) {
35098d7f2e76SPhilippe Mathieu-Daudé             ml = g_new(MemoryRegionList, 1);
35108d7f2e76SPhilippe Mathieu-Daudé             ml->mr = mr->alias;
35118d7f2e76SPhilippe Mathieu-Daudé             QTAILQ_INSERT_TAIL(alias_print_queue, ml, mrqueue);
35128d7f2e76SPhilippe Mathieu-Daudé         }
35138d7f2e76SPhilippe Mathieu-Daudé         if (mr->enabled || display_disabled) {
35148d7f2e76SPhilippe Mathieu-Daudé             for (i = 0; i < level; i++) {
35158d7f2e76SPhilippe Mathieu-Daudé                 qemu_printf(MTREE_INDENT);
35168d7f2e76SPhilippe Mathieu-Daudé             }
35178d7f2e76SPhilippe Mathieu-Daudé             qemu_printf(HWADDR_FMT_plx "-" HWADDR_FMT_plx
35188d7f2e76SPhilippe Mathieu-Daudé                         " (prio %d, %s%s): alias %s @%s " HWADDR_FMT_plx
35198d7f2e76SPhilippe Mathieu-Daudé                         "-" HWADDR_FMT_plx "%s",
35208d7f2e76SPhilippe Mathieu-Daudé                         cur_start, cur_end,
35218d7f2e76SPhilippe Mathieu-Daudé                         mr->priority,
35228d7f2e76SPhilippe Mathieu-Daudé                         mr->nonvolatile ? "nv-" : "",
35238d7f2e76SPhilippe Mathieu-Daudé                         memory_region_type((MemoryRegion *)mr),
35248d7f2e76SPhilippe Mathieu-Daudé                         memory_region_name(mr),
35258d7f2e76SPhilippe Mathieu-Daudé                         memory_region_name(mr->alias),
35268d7f2e76SPhilippe Mathieu-Daudé                         mr->alias_offset,
35278d7f2e76SPhilippe Mathieu-Daudé                         mr->alias_offset + MR_SIZE(mr->size),
35288d7f2e76SPhilippe Mathieu-Daudé                         mr->enabled ? "" : " [disabled]");
35298d7f2e76SPhilippe Mathieu-Daudé             if (owner) {
35308d7f2e76SPhilippe Mathieu-Daudé                 mtree_print_mr_owner(mr);
35318d7f2e76SPhilippe Mathieu-Daudé             }
35328d7f2e76SPhilippe Mathieu-Daudé             qemu_printf("\n");
35338d7f2e76SPhilippe Mathieu-Daudé         }
35348d7f2e76SPhilippe Mathieu-Daudé     } else {
35358d7f2e76SPhilippe Mathieu-Daudé         if (mr->enabled || display_disabled) {
35368d7f2e76SPhilippe Mathieu-Daudé             for (i = 0; i < level; i++) {
35378d7f2e76SPhilippe Mathieu-Daudé                 qemu_printf(MTREE_INDENT);
35388d7f2e76SPhilippe Mathieu-Daudé             }
35398d7f2e76SPhilippe Mathieu-Daudé             qemu_printf(HWADDR_FMT_plx "-" HWADDR_FMT_plx
35408d7f2e76SPhilippe Mathieu-Daudé                         " (prio %d, %s%s): %s%s",
35418d7f2e76SPhilippe Mathieu-Daudé                         cur_start, cur_end,
35428d7f2e76SPhilippe Mathieu-Daudé                         mr->priority,
35438d7f2e76SPhilippe Mathieu-Daudé                         mr->nonvolatile ? "nv-" : "",
35448d7f2e76SPhilippe Mathieu-Daudé                         memory_region_type((MemoryRegion *)mr),
35458d7f2e76SPhilippe Mathieu-Daudé                         memory_region_name(mr),
35468d7f2e76SPhilippe Mathieu-Daudé                         mr->enabled ? "" : " [disabled]");
35478d7f2e76SPhilippe Mathieu-Daudé             if (owner) {
35488d7f2e76SPhilippe Mathieu-Daudé                 mtree_print_mr_owner(mr);
35498d7f2e76SPhilippe Mathieu-Daudé             }
35508d7f2e76SPhilippe Mathieu-Daudé             qemu_printf("\n");
35518d7f2e76SPhilippe Mathieu-Daudé         }
35528d7f2e76SPhilippe Mathieu-Daudé     }
35538d7f2e76SPhilippe Mathieu-Daudé 
35548d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_INIT(&submr_print_queue);
35558d7f2e76SPhilippe Mathieu-Daudé 
35568d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(submr, &mr->subregions, subregions_link) {
35578d7f2e76SPhilippe Mathieu-Daudé         new_ml = g_new(MemoryRegionList, 1);
35588d7f2e76SPhilippe Mathieu-Daudé         new_ml->mr = submr;
35598d7f2e76SPhilippe Mathieu-Daudé         QTAILQ_FOREACH(ml, &submr_print_queue, mrqueue) {
35608d7f2e76SPhilippe Mathieu-Daudé             if (new_ml->mr->addr < ml->mr->addr ||
35618d7f2e76SPhilippe Mathieu-Daudé                 (new_ml->mr->addr == ml->mr->addr &&
35628d7f2e76SPhilippe Mathieu-Daudé                  new_ml->mr->priority > ml->mr->priority)) {
35638d7f2e76SPhilippe Mathieu-Daudé                 QTAILQ_INSERT_BEFORE(ml, new_ml, mrqueue);
35648d7f2e76SPhilippe Mathieu-Daudé                 new_ml = NULL;
35658d7f2e76SPhilippe Mathieu-Daudé                 break;
35668d7f2e76SPhilippe Mathieu-Daudé             }
35678d7f2e76SPhilippe Mathieu-Daudé         }
35688d7f2e76SPhilippe Mathieu-Daudé         if (new_ml) {
35698d7f2e76SPhilippe Mathieu-Daudé             QTAILQ_INSERT_TAIL(&submr_print_queue, new_ml, mrqueue);
35708d7f2e76SPhilippe Mathieu-Daudé         }
35718d7f2e76SPhilippe Mathieu-Daudé     }
35728d7f2e76SPhilippe Mathieu-Daudé 
35738d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(ml, &submr_print_queue, mrqueue) {
35748d7f2e76SPhilippe Mathieu-Daudé         mtree_print_mr(ml->mr, level + 1, cur_start,
35758d7f2e76SPhilippe Mathieu-Daudé                        alias_print_queue, owner, display_disabled);
35768d7f2e76SPhilippe Mathieu-Daudé     }
35778d7f2e76SPhilippe Mathieu-Daudé 
35788d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH_SAFE(ml, &submr_print_queue, mrqueue, next_ml) {
35798d7f2e76SPhilippe Mathieu-Daudé         g_free(ml);
35808d7f2e76SPhilippe Mathieu-Daudé     }
35818d7f2e76SPhilippe Mathieu-Daudé }
35828d7f2e76SPhilippe Mathieu-Daudé 
35838d7f2e76SPhilippe Mathieu-Daudé struct FlatViewInfo {
35848d7f2e76SPhilippe Mathieu-Daudé     int counter;
35858d7f2e76SPhilippe Mathieu-Daudé     bool dispatch_tree;
35868d7f2e76SPhilippe Mathieu-Daudé     bool owner;
35878d7f2e76SPhilippe Mathieu-Daudé     AccelClass *ac;
35888d7f2e76SPhilippe Mathieu-Daudé };
35898d7f2e76SPhilippe Mathieu-Daudé 
mtree_print_flatview(gpointer key,gpointer value,gpointer user_data)35908d7f2e76SPhilippe Mathieu-Daudé static void mtree_print_flatview(gpointer key, gpointer value,
35918d7f2e76SPhilippe Mathieu-Daudé                                  gpointer user_data)
35928d7f2e76SPhilippe Mathieu-Daudé {
35938d7f2e76SPhilippe Mathieu-Daudé     FlatView *view = key;
35948d7f2e76SPhilippe Mathieu-Daudé     GArray *fv_address_spaces = value;
35958d7f2e76SPhilippe Mathieu-Daudé     struct FlatViewInfo *fvi = user_data;
35968d7f2e76SPhilippe Mathieu-Daudé     FlatRange *range = &view->ranges[0];
35978d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr;
35988d7f2e76SPhilippe Mathieu-Daudé     int n = view->nr;
35998d7f2e76SPhilippe Mathieu-Daudé     int i;
36008d7f2e76SPhilippe Mathieu-Daudé     AddressSpace *as;
36018d7f2e76SPhilippe Mathieu-Daudé 
36028d7f2e76SPhilippe Mathieu-Daudé     qemu_printf("FlatView #%d\n", fvi->counter);
36038d7f2e76SPhilippe Mathieu-Daudé     ++fvi->counter;
36048d7f2e76SPhilippe Mathieu-Daudé 
36058d7f2e76SPhilippe Mathieu-Daudé     for (i = 0; i < fv_address_spaces->len; ++i) {
36068d7f2e76SPhilippe Mathieu-Daudé         as = g_array_index(fv_address_spaces, AddressSpace*, i);
36078d7f2e76SPhilippe Mathieu-Daudé         qemu_printf(" AS \"%s\", root: %s",
36088d7f2e76SPhilippe Mathieu-Daudé                     as->name, memory_region_name(as->root));
36098d7f2e76SPhilippe Mathieu-Daudé         if (as->root->alias) {
36108d7f2e76SPhilippe Mathieu-Daudé             qemu_printf(", alias %s", memory_region_name(as->root->alias));
36118d7f2e76SPhilippe Mathieu-Daudé         }
36128d7f2e76SPhilippe Mathieu-Daudé         qemu_printf("\n");
36138d7f2e76SPhilippe Mathieu-Daudé     }
36148d7f2e76SPhilippe Mathieu-Daudé 
36158d7f2e76SPhilippe Mathieu-Daudé     qemu_printf(" Root memory region: %s\n",
36168d7f2e76SPhilippe Mathieu-Daudé       view->root ? memory_region_name(view->root) : "(none)");
36178d7f2e76SPhilippe Mathieu-Daudé 
36188d7f2e76SPhilippe Mathieu-Daudé     if (n <= 0) {
36198d7f2e76SPhilippe Mathieu-Daudé         qemu_printf(MTREE_INDENT "No rendered FlatView\n\n");
36208d7f2e76SPhilippe Mathieu-Daudé         return;
36218d7f2e76SPhilippe Mathieu-Daudé     }
36228d7f2e76SPhilippe Mathieu-Daudé 
36238d7f2e76SPhilippe Mathieu-Daudé     while (n--) {
36248d7f2e76SPhilippe Mathieu-Daudé         mr = range->mr;
36258d7f2e76SPhilippe Mathieu-Daudé         if (range->offset_in_region) {
36268d7f2e76SPhilippe Mathieu-Daudé             qemu_printf(MTREE_INDENT HWADDR_FMT_plx "-" HWADDR_FMT_plx
36278d7f2e76SPhilippe Mathieu-Daudé                         " (prio %d, %s%s): %s @" HWADDR_FMT_plx,
36288d7f2e76SPhilippe Mathieu-Daudé                         int128_get64(range->addr.start),
36298d7f2e76SPhilippe Mathieu-Daudé                         int128_get64(range->addr.start)
36308d7f2e76SPhilippe Mathieu-Daudé                         + MR_SIZE(range->addr.size),
36318d7f2e76SPhilippe Mathieu-Daudé                         mr->priority,
36328d7f2e76SPhilippe Mathieu-Daudé                         range->nonvolatile ? "nv-" : "",
36338d7f2e76SPhilippe Mathieu-Daudé                         range->readonly ? "rom" : memory_region_type(mr),
36348d7f2e76SPhilippe Mathieu-Daudé                         memory_region_name(mr),
36358d7f2e76SPhilippe Mathieu-Daudé                         range->offset_in_region);
36368d7f2e76SPhilippe Mathieu-Daudé         } else {
36378d7f2e76SPhilippe Mathieu-Daudé             qemu_printf(MTREE_INDENT HWADDR_FMT_plx "-" HWADDR_FMT_plx
36388d7f2e76SPhilippe Mathieu-Daudé                         " (prio %d, %s%s): %s",
36398d7f2e76SPhilippe Mathieu-Daudé                         int128_get64(range->addr.start),
36408d7f2e76SPhilippe Mathieu-Daudé                         int128_get64(range->addr.start)
36418d7f2e76SPhilippe Mathieu-Daudé                         + MR_SIZE(range->addr.size),
36428d7f2e76SPhilippe Mathieu-Daudé                         mr->priority,
36438d7f2e76SPhilippe Mathieu-Daudé                         range->nonvolatile ? "nv-" : "",
36448d7f2e76SPhilippe Mathieu-Daudé                         range->readonly ? "rom" : memory_region_type(mr),
36458d7f2e76SPhilippe Mathieu-Daudé                         memory_region_name(mr));
36468d7f2e76SPhilippe Mathieu-Daudé         }
36478d7f2e76SPhilippe Mathieu-Daudé         if (fvi->owner) {
36488d7f2e76SPhilippe Mathieu-Daudé             mtree_print_mr_owner(mr);
36498d7f2e76SPhilippe Mathieu-Daudé         }
36508d7f2e76SPhilippe Mathieu-Daudé 
36518d7f2e76SPhilippe Mathieu-Daudé         if (fvi->ac) {
36528d7f2e76SPhilippe Mathieu-Daudé             for (i = 0; i < fv_address_spaces->len; ++i) {
36538d7f2e76SPhilippe Mathieu-Daudé                 as = g_array_index(fv_address_spaces, AddressSpace*, i);
36548d7f2e76SPhilippe Mathieu-Daudé                 if (fvi->ac->has_memory(current_machine, as,
36558d7f2e76SPhilippe Mathieu-Daudé                                         int128_get64(range->addr.start),
36568d7f2e76SPhilippe Mathieu-Daudé                                         MR_SIZE(range->addr.size) + 1)) {
36578d7f2e76SPhilippe Mathieu-Daudé                     qemu_printf(" %s", fvi->ac->name);
36588d7f2e76SPhilippe Mathieu-Daudé                 }
36598d7f2e76SPhilippe Mathieu-Daudé             }
36608d7f2e76SPhilippe Mathieu-Daudé         }
36618d7f2e76SPhilippe Mathieu-Daudé         qemu_printf("\n");
36628d7f2e76SPhilippe Mathieu-Daudé         range++;
36638d7f2e76SPhilippe Mathieu-Daudé     }
36648d7f2e76SPhilippe Mathieu-Daudé 
36658d7f2e76SPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
36668d7f2e76SPhilippe Mathieu-Daudé     if (fvi->dispatch_tree && view->root) {
36678d7f2e76SPhilippe Mathieu-Daudé         mtree_print_dispatch(view->dispatch, view->root);
36688d7f2e76SPhilippe Mathieu-Daudé     }
36698d7f2e76SPhilippe Mathieu-Daudé #endif
36708d7f2e76SPhilippe Mathieu-Daudé 
36718d7f2e76SPhilippe Mathieu-Daudé     qemu_printf("\n");
36728d7f2e76SPhilippe Mathieu-Daudé }
36738d7f2e76SPhilippe Mathieu-Daudé 
mtree_info_flatview_free(gpointer key,gpointer value,gpointer user_data)36748d7f2e76SPhilippe Mathieu-Daudé static gboolean mtree_info_flatview_free(gpointer key, gpointer value,
36758d7f2e76SPhilippe Mathieu-Daudé                                       gpointer user_data)
36768d7f2e76SPhilippe Mathieu-Daudé {
36778d7f2e76SPhilippe Mathieu-Daudé     FlatView *view = key;
36788d7f2e76SPhilippe Mathieu-Daudé     GArray *fv_address_spaces = value;
36798d7f2e76SPhilippe Mathieu-Daudé 
36808d7f2e76SPhilippe Mathieu-Daudé     g_array_unref(fv_address_spaces);
36818d7f2e76SPhilippe Mathieu-Daudé     flatview_unref(view);
36828d7f2e76SPhilippe Mathieu-Daudé 
36838d7f2e76SPhilippe Mathieu-Daudé     return true;
36848d7f2e76SPhilippe Mathieu-Daudé }
36858d7f2e76SPhilippe Mathieu-Daudé 
mtree_info_flatview(bool dispatch_tree,bool owner)36868d7f2e76SPhilippe Mathieu-Daudé static void mtree_info_flatview(bool dispatch_tree, bool owner)
36878d7f2e76SPhilippe Mathieu-Daudé {
36888d7f2e76SPhilippe Mathieu-Daudé     struct FlatViewInfo fvi = {
36898d7f2e76SPhilippe Mathieu-Daudé         .counter = 0,
36908d7f2e76SPhilippe Mathieu-Daudé         .dispatch_tree = dispatch_tree,
36918d7f2e76SPhilippe Mathieu-Daudé         .owner = owner,
36928d7f2e76SPhilippe Mathieu-Daudé     };
36938d7f2e76SPhilippe Mathieu-Daudé     AddressSpace *as;
36948d7f2e76SPhilippe Mathieu-Daudé     FlatView *view;
36958d7f2e76SPhilippe Mathieu-Daudé     GArray *fv_address_spaces;
36968d7f2e76SPhilippe Mathieu-Daudé     GHashTable *views = g_hash_table_new(g_direct_hash, g_direct_equal);
36978d7f2e76SPhilippe Mathieu-Daudé     AccelClass *ac = ACCEL_GET_CLASS(current_accel());
36988d7f2e76SPhilippe Mathieu-Daudé 
36998d7f2e76SPhilippe Mathieu-Daudé     if (ac->has_memory) {
37008d7f2e76SPhilippe Mathieu-Daudé         fvi.ac = ac;
37018d7f2e76SPhilippe Mathieu-Daudé     }
37028d7f2e76SPhilippe Mathieu-Daudé 
37038d7f2e76SPhilippe Mathieu-Daudé     /* Gather all FVs in one table */
37048d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
37058d7f2e76SPhilippe Mathieu-Daudé         view = address_space_get_flatview(as);
37068d7f2e76SPhilippe Mathieu-Daudé 
37078d7f2e76SPhilippe Mathieu-Daudé         fv_address_spaces = g_hash_table_lookup(views, view);
37088d7f2e76SPhilippe Mathieu-Daudé         if (!fv_address_spaces) {
37098d7f2e76SPhilippe Mathieu-Daudé             fv_address_spaces = g_array_new(false, false, sizeof(as));
37108d7f2e76SPhilippe Mathieu-Daudé             g_hash_table_insert(views, view, fv_address_spaces);
37118d7f2e76SPhilippe Mathieu-Daudé         }
37128d7f2e76SPhilippe Mathieu-Daudé 
37138d7f2e76SPhilippe Mathieu-Daudé         g_array_append_val(fv_address_spaces, as);
37148d7f2e76SPhilippe Mathieu-Daudé     }
37158d7f2e76SPhilippe Mathieu-Daudé 
37168d7f2e76SPhilippe Mathieu-Daudé     /* Print */
37178d7f2e76SPhilippe Mathieu-Daudé     g_hash_table_foreach(views, mtree_print_flatview, &fvi);
37188d7f2e76SPhilippe Mathieu-Daudé 
37198d7f2e76SPhilippe Mathieu-Daudé     /* Free */
37208d7f2e76SPhilippe Mathieu-Daudé     g_hash_table_foreach_remove(views, mtree_info_flatview_free, 0);
37218d7f2e76SPhilippe Mathieu-Daudé     g_hash_table_unref(views);
37228d7f2e76SPhilippe Mathieu-Daudé }
37238d7f2e76SPhilippe Mathieu-Daudé 
37248d7f2e76SPhilippe Mathieu-Daudé struct AddressSpaceInfo {
37258d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionListHead *ml_head;
37268d7f2e76SPhilippe Mathieu-Daudé     bool owner;
37278d7f2e76SPhilippe Mathieu-Daudé     bool disabled;
37288d7f2e76SPhilippe Mathieu-Daudé };
37298d7f2e76SPhilippe Mathieu-Daudé 
37308d7f2e76SPhilippe Mathieu-Daudé /* Returns negative value if a < b; zero if a = b; positive value if a > b. */
address_space_compare_name(gconstpointer a,gconstpointer b)37318d7f2e76SPhilippe Mathieu-Daudé static gint address_space_compare_name(gconstpointer a, gconstpointer b)
37328d7f2e76SPhilippe Mathieu-Daudé {
37338d7f2e76SPhilippe Mathieu-Daudé     const AddressSpace *as_a = a;
37348d7f2e76SPhilippe Mathieu-Daudé     const AddressSpace *as_b = b;
37358d7f2e76SPhilippe Mathieu-Daudé 
37368d7f2e76SPhilippe Mathieu-Daudé     return g_strcmp0(as_a->name, as_b->name);
37378d7f2e76SPhilippe Mathieu-Daudé }
37388d7f2e76SPhilippe Mathieu-Daudé 
mtree_print_as_name(gpointer data,gpointer user_data)37398d7f2e76SPhilippe Mathieu-Daudé static void mtree_print_as_name(gpointer data, gpointer user_data)
37408d7f2e76SPhilippe Mathieu-Daudé {
37418d7f2e76SPhilippe Mathieu-Daudé     AddressSpace *as = data;
37428d7f2e76SPhilippe Mathieu-Daudé 
37438d7f2e76SPhilippe Mathieu-Daudé     qemu_printf("address-space: %s\n", as->name);
37448d7f2e76SPhilippe Mathieu-Daudé }
37458d7f2e76SPhilippe Mathieu-Daudé 
mtree_print_as(gpointer key,gpointer value,gpointer user_data)37468d7f2e76SPhilippe Mathieu-Daudé static void mtree_print_as(gpointer key, gpointer value, gpointer user_data)
37478d7f2e76SPhilippe Mathieu-Daudé {
37488d7f2e76SPhilippe Mathieu-Daudé     MemoryRegion *mr = key;
37498d7f2e76SPhilippe Mathieu-Daudé     GSList *as_same_root_mr_list = value;
37508d7f2e76SPhilippe Mathieu-Daudé     struct AddressSpaceInfo *asi = user_data;
37518d7f2e76SPhilippe Mathieu-Daudé 
37528d7f2e76SPhilippe Mathieu-Daudé     g_slist_foreach(as_same_root_mr_list, mtree_print_as_name, NULL);
37538d7f2e76SPhilippe Mathieu-Daudé     mtree_print_mr(mr, 1, 0, asi->ml_head, asi->owner, asi->disabled);
37548d7f2e76SPhilippe Mathieu-Daudé     qemu_printf("\n");
37558d7f2e76SPhilippe Mathieu-Daudé }
37568d7f2e76SPhilippe Mathieu-Daudé 
mtree_info_as_free(gpointer key,gpointer value,gpointer user_data)37578d7f2e76SPhilippe Mathieu-Daudé static gboolean mtree_info_as_free(gpointer key, gpointer value,
37588d7f2e76SPhilippe Mathieu-Daudé                                    gpointer user_data)
37598d7f2e76SPhilippe Mathieu-Daudé {
37608d7f2e76SPhilippe Mathieu-Daudé     GSList *as_same_root_mr_list = value;
37618d7f2e76SPhilippe Mathieu-Daudé 
37628d7f2e76SPhilippe Mathieu-Daudé     g_slist_free(as_same_root_mr_list);
37638d7f2e76SPhilippe Mathieu-Daudé 
37648d7f2e76SPhilippe Mathieu-Daudé     return true;
37658d7f2e76SPhilippe Mathieu-Daudé }
37668d7f2e76SPhilippe Mathieu-Daudé 
mtree_info_as(bool dispatch_tree,bool owner,bool disabled)37678d7f2e76SPhilippe Mathieu-Daudé static void mtree_info_as(bool dispatch_tree, bool owner, bool disabled)
37688d7f2e76SPhilippe Mathieu-Daudé {
37698d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionListHead ml_head;
37708d7f2e76SPhilippe Mathieu-Daudé     MemoryRegionList *ml, *ml2;
37718d7f2e76SPhilippe Mathieu-Daudé     AddressSpace *as;
37728d7f2e76SPhilippe Mathieu-Daudé     GHashTable *views = g_hash_table_new(g_direct_hash, g_direct_equal);
37738d7f2e76SPhilippe Mathieu-Daudé     GSList *as_same_root_mr_list;
37748d7f2e76SPhilippe Mathieu-Daudé     struct AddressSpaceInfo asi = {
37758d7f2e76SPhilippe Mathieu-Daudé         .ml_head = &ml_head,
37768d7f2e76SPhilippe Mathieu-Daudé         .owner = owner,
37778d7f2e76SPhilippe Mathieu-Daudé         .disabled = disabled,
37788d7f2e76SPhilippe Mathieu-Daudé     };
37798d7f2e76SPhilippe Mathieu-Daudé 
37808d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_INIT(&ml_head);
37818d7f2e76SPhilippe Mathieu-Daudé 
37828d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
37838d7f2e76SPhilippe Mathieu-Daudé         /* Create hashtable, key=AS root MR, value = list of AS */
37848d7f2e76SPhilippe Mathieu-Daudé         as_same_root_mr_list = g_hash_table_lookup(views, as->root);
37858d7f2e76SPhilippe Mathieu-Daudé         as_same_root_mr_list = g_slist_insert_sorted(as_same_root_mr_list, as,
37868d7f2e76SPhilippe Mathieu-Daudé                                                      address_space_compare_name);
37878d7f2e76SPhilippe Mathieu-Daudé         g_hash_table_insert(views, as->root, as_same_root_mr_list);
37888d7f2e76SPhilippe Mathieu-Daudé     }
37898d7f2e76SPhilippe Mathieu-Daudé 
37908d7f2e76SPhilippe Mathieu-Daudé     /* print address spaces */
37918d7f2e76SPhilippe Mathieu-Daudé     g_hash_table_foreach(views, mtree_print_as, &asi);
37928d7f2e76SPhilippe Mathieu-Daudé     g_hash_table_foreach_remove(views, mtree_info_as_free, 0);
37938d7f2e76SPhilippe Mathieu-Daudé     g_hash_table_unref(views);
37948d7f2e76SPhilippe Mathieu-Daudé 
37958d7f2e76SPhilippe Mathieu-Daudé     /* print aliased regions */
37968d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH(ml, &ml_head, mrqueue) {
37978d7f2e76SPhilippe Mathieu-Daudé         qemu_printf("memory-region: %s\n", memory_region_name(ml->mr));
37988d7f2e76SPhilippe Mathieu-Daudé         mtree_print_mr(ml->mr, 1, 0, &ml_head, owner, disabled);
37998d7f2e76SPhilippe Mathieu-Daudé         qemu_printf("\n");
38008d7f2e76SPhilippe Mathieu-Daudé     }
38018d7f2e76SPhilippe Mathieu-Daudé 
38028d7f2e76SPhilippe Mathieu-Daudé     QTAILQ_FOREACH_SAFE(ml, &ml_head, mrqueue, ml2) {
38038d7f2e76SPhilippe Mathieu-Daudé         g_free(ml);
38048d7f2e76SPhilippe Mathieu-Daudé     }
38058d7f2e76SPhilippe Mathieu-Daudé }
38068d7f2e76SPhilippe Mathieu-Daudé 
mtree_info(bool flatview,bool dispatch_tree,bool owner,bool disabled)38078d7f2e76SPhilippe Mathieu-Daudé void mtree_info(bool flatview, bool dispatch_tree, bool owner, bool disabled)
38088d7f2e76SPhilippe Mathieu-Daudé {
38098d7f2e76SPhilippe Mathieu-Daudé     if (flatview) {
38108d7f2e76SPhilippe Mathieu-Daudé         mtree_info_flatview(dispatch_tree, owner);
38118d7f2e76SPhilippe Mathieu-Daudé     } else {
38128d7f2e76SPhilippe Mathieu-Daudé         mtree_info_as(dispatch_tree, owner, disabled);
38138d7f2e76SPhilippe Mathieu-Daudé     }
38148d7f2e76SPhilippe Mathieu-Daudé }
38158d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_ram(MemoryRegion * mr,Object * owner,const char * name,uint64_t size,Error ** errp)3816fe5f33d6SPhilippe Mathieu-Daudé bool memory_region_init_ram(MemoryRegion *mr,
38178d7f2e76SPhilippe Mathieu-Daudé                             Object *owner,
38188d7f2e76SPhilippe Mathieu-Daudé                             const char *name,
38198d7f2e76SPhilippe Mathieu-Daudé                             uint64_t size,
38208d7f2e76SPhilippe Mathieu-Daudé                             Error **errp)
38218d7f2e76SPhilippe Mathieu-Daudé {
38228d7f2e76SPhilippe Mathieu-Daudé     DeviceState *owner_dev;
38238d7f2e76SPhilippe Mathieu-Daudé 
3824d3143bd5SPhilippe Mathieu-Daudé     if (!memory_region_init_ram_nomigrate(mr, owner, name, size, errp)) {
3825fe5f33d6SPhilippe Mathieu-Daudé         return false;
38268d7f2e76SPhilippe Mathieu-Daudé     }
38278d7f2e76SPhilippe Mathieu-Daudé     /* This will assert if owner is neither NULL nor a DeviceState.
38288d7f2e76SPhilippe Mathieu-Daudé      * We only want the owner here for the purposes of defining a
38298d7f2e76SPhilippe Mathieu-Daudé      * unique name for migration. TODO: Ideally we should implement
38308d7f2e76SPhilippe Mathieu-Daudé      * a naming scheme for Objects which are not DeviceStates, in
38318d7f2e76SPhilippe Mathieu-Daudé      * which case we can relax this restriction.
38328d7f2e76SPhilippe Mathieu-Daudé      */
38338d7f2e76SPhilippe Mathieu-Daudé     owner_dev = DEVICE(owner);
38348d7f2e76SPhilippe Mathieu-Daudé     vmstate_register_ram(mr, owner_dev);
3835fe5f33d6SPhilippe Mathieu-Daudé 
3836fe5f33d6SPhilippe Mathieu-Daudé     return true;
38378d7f2e76SPhilippe Mathieu-Daudé }
38388d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_ram_guest_memfd(MemoryRegion * mr,Object * owner,const char * name,uint64_t size,Error ** errp)3839a0aa6db7SXiaoyao Li bool memory_region_init_ram_guest_memfd(MemoryRegion *mr,
3840a0aa6db7SXiaoyao Li                                         Object *owner,
3841a0aa6db7SXiaoyao Li                                         const char *name,
3842a0aa6db7SXiaoyao Li                                         uint64_t size,
3843a0aa6db7SXiaoyao Li                                         Error **errp)
3844a0aa6db7SXiaoyao Li {
3845a0aa6db7SXiaoyao Li     DeviceState *owner_dev;
3846a0aa6db7SXiaoyao Li 
3847a0aa6db7SXiaoyao Li     if (!memory_region_init_ram_flags_nomigrate(mr, owner, name, size,
3848a0aa6db7SXiaoyao Li                                                 RAM_GUEST_MEMFD, errp)) {
3849a0aa6db7SXiaoyao Li         return false;
3850a0aa6db7SXiaoyao Li     }
3851a0aa6db7SXiaoyao Li     /* This will assert if owner is neither NULL nor a DeviceState.
3852a0aa6db7SXiaoyao Li      * We only want the owner here for the purposes of defining a
3853a0aa6db7SXiaoyao Li      * unique name for migration. TODO: Ideally we should implement
3854a0aa6db7SXiaoyao Li      * a naming scheme for Objects which are not DeviceStates, in
3855a0aa6db7SXiaoyao Li      * which case we can relax this restriction.
3856a0aa6db7SXiaoyao Li      */
3857a0aa6db7SXiaoyao Li     owner_dev = DEVICE(owner);
3858a0aa6db7SXiaoyao Li     vmstate_register_ram(mr, owner_dev);
3859a0aa6db7SXiaoyao Li 
3860a0aa6db7SXiaoyao Li     return true;
3861a0aa6db7SXiaoyao Li }
3862a0aa6db7SXiaoyao Li 
memory_region_init_rom(MemoryRegion * mr,Object * owner,const char * name,uint64_t size,Error ** errp)3863b9159451SPhilippe Mathieu-Daudé bool memory_region_init_rom(MemoryRegion *mr,
38648d7f2e76SPhilippe Mathieu-Daudé                             Object *owner,
38658d7f2e76SPhilippe Mathieu-Daudé                             const char *name,
38668d7f2e76SPhilippe Mathieu-Daudé                             uint64_t size,
38678d7f2e76SPhilippe Mathieu-Daudé                             Error **errp)
38688d7f2e76SPhilippe Mathieu-Daudé {
38698d7f2e76SPhilippe Mathieu-Daudé     DeviceState *owner_dev;
38708d7f2e76SPhilippe Mathieu-Daudé 
3871fd7549eeSPhilippe Mathieu-Daudé     if (!memory_region_init_rom_nomigrate(mr, owner, name, size, errp)) {
3872b9159451SPhilippe Mathieu-Daudé         return false;
38738d7f2e76SPhilippe Mathieu-Daudé     }
38748d7f2e76SPhilippe Mathieu-Daudé     /* This will assert if owner is neither NULL nor a DeviceState.
38758d7f2e76SPhilippe Mathieu-Daudé      * We only want the owner here for the purposes of defining a
38768d7f2e76SPhilippe Mathieu-Daudé      * unique name for migration. TODO: Ideally we should implement
38778d7f2e76SPhilippe Mathieu-Daudé      * a naming scheme for Objects which are not DeviceStates, in
38788d7f2e76SPhilippe Mathieu-Daudé      * which case we can relax this restriction.
38798d7f2e76SPhilippe Mathieu-Daudé      */
38808d7f2e76SPhilippe Mathieu-Daudé     owner_dev = DEVICE(owner);
38818d7f2e76SPhilippe Mathieu-Daudé     vmstate_register_ram(mr, owner_dev);
3882b9159451SPhilippe Mathieu-Daudé 
3883b9159451SPhilippe Mathieu-Daudé     return true;
38848d7f2e76SPhilippe Mathieu-Daudé }
38858d7f2e76SPhilippe Mathieu-Daudé 
memory_region_init_rom_device(MemoryRegion * mr,Object * owner,const MemoryRegionOps * ops,void * opaque,const char * name,uint64_t size,Error ** errp)388662f5c1b2SPhilippe Mathieu-Daudé bool memory_region_init_rom_device(MemoryRegion *mr,
38878d7f2e76SPhilippe Mathieu-Daudé                                    Object *owner,
38888d7f2e76SPhilippe Mathieu-Daudé                                    const MemoryRegionOps *ops,
38898d7f2e76SPhilippe Mathieu-Daudé                                    void *opaque,
38908d7f2e76SPhilippe Mathieu-Daudé                                    const char *name,
38918d7f2e76SPhilippe Mathieu-Daudé                                    uint64_t size,
38928d7f2e76SPhilippe Mathieu-Daudé                                    Error **errp)
38938d7f2e76SPhilippe Mathieu-Daudé {
38948d7f2e76SPhilippe Mathieu-Daudé     DeviceState *owner_dev;
38958d7f2e76SPhilippe Mathieu-Daudé 
3896bd3aa069SPhilippe Mathieu-Daudé     if (!memory_region_init_rom_device_nomigrate(mr, owner, ops, opaque,
3897bd3aa069SPhilippe Mathieu-Daudé                                                  name, size, errp)) {
389862f5c1b2SPhilippe Mathieu-Daudé         return false;
38998d7f2e76SPhilippe Mathieu-Daudé     }
39008d7f2e76SPhilippe Mathieu-Daudé     /* This will assert if owner is neither NULL nor a DeviceState.
39018d7f2e76SPhilippe Mathieu-Daudé      * We only want the owner here for the purposes of defining a
39028d7f2e76SPhilippe Mathieu-Daudé      * unique name for migration. TODO: Ideally we should implement
39038d7f2e76SPhilippe Mathieu-Daudé      * a naming scheme for Objects which are not DeviceStates, in
39048d7f2e76SPhilippe Mathieu-Daudé      * which case we can relax this restriction.
39058d7f2e76SPhilippe Mathieu-Daudé      */
39068d7f2e76SPhilippe Mathieu-Daudé     owner_dev = DEVICE(owner);
39078d7f2e76SPhilippe Mathieu-Daudé     vmstate_register_ram(mr, owner_dev);
390862f5c1b2SPhilippe Mathieu-Daudé 
390962f5c1b2SPhilippe Mathieu-Daudé     return true;
39108d7f2e76SPhilippe Mathieu-Daudé }
39118d7f2e76SPhilippe Mathieu-Daudé 
39128d7f2e76SPhilippe Mathieu-Daudé /*
39138d7f2e76SPhilippe Mathieu-Daudé  * Support system builds with CONFIG_FUZZ using a weak symbol and a stub for
39148d7f2e76SPhilippe Mathieu-Daudé  * the fuzz_dma_read_cb callback
39158d7f2e76SPhilippe Mathieu-Daudé  */
39168d7f2e76SPhilippe Mathieu-Daudé #ifdef CONFIG_FUZZ
fuzz_dma_read_cb(size_t addr,size_t len,MemoryRegion * mr)39178d7f2e76SPhilippe Mathieu-Daudé void __attribute__((weak)) fuzz_dma_read_cb(size_t addr,
39188d7f2e76SPhilippe Mathieu-Daudé                       size_t len,
39198d7f2e76SPhilippe Mathieu-Daudé                       MemoryRegion *mr)
39208d7f2e76SPhilippe Mathieu-Daudé {
39218d7f2e76SPhilippe Mathieu-Daudé }
39228d7f2e76SPhilippe Mathieu-Daudé #endif
39238d7f2e76SPhilippe Mathieu-Daudé 
39248d7f2e76SPhilippe Mathieu-Daudé static const TypeInfo memory_region_info = {
39258d7f2e76SPhilippe Mathieu-Daudé     .parent             = TYPE_OBJECT,
39268d7f2e76SPhilippe Mathieu-Daudé     .name               = TYPE_MEMORY_REGION,
39278d7f2e76SPhilippe Mathieu-Daudé     .class_size         = sizeof(MemoryRegionClass),
39288d7f2e76SPhilippe Mathieu-Daudé     .instance_size      = sizeof(MemoryRegion),
39298d7f2e76SPhilippe Mathieu-Daudé     .instance_init      = memory_region_initfn,
39308d7f2e76SPhilippe Mathieu-Daudé     .instance_finalize  = memory_region_finalize,
39318d7f2e76SPhilippe Mathieu-Daudé };
39328d7f2e76SPhilippe Mathieu-Daudé 
39338d7f2e76SPhilippe Mathieu-Daudé static const TypeInfo iommu_memory_region_info = {
39348d7f2e76SPhilippe Mathieu-Daudé     .parent             = TYPE_MEMORY_REGION,
39358d7f2e76SPhilippe Mathieu-Daudé     .name               = TYPE_IOMMU_MEMORY_REGION,
39368d7f2e76SPhilippe Mathieu-Daudé     .class_size         = sizeof(IOMMUMemoryRegionClass),
39378d7f2e76SPhilippe Mathieu-Daudé     .instance_size      = sizeof(IOMMUMemoryRegion),
39388d7f2e76SPhilippe Mathieu-Daudé     .instance_init      = iommu_memory_region_initfn,
39398d7f2e76SPhilippe Mathieu-Daudé     .abstract           = true,
39408d7f2e76SPhilippe Mathieu-Daudé };
39418d7f2e76SPhilippe Mathieu-Daudé 
39428d7f2e76SPhilippe Mathieu-Daudé static const TypeInfo ram_discard_manager_info = {
39438d7f2e76SPhilippe Mathieu-Daudé     .parent             = TYPE_INTERFACE,
39448d7f2e76SPhilippe Mathieu-Daudé     .name               = TYPE_RAM_DISCARD_MANAGER,
39458d7f2e76SPhilippe Mathieu-Daudé     .class_size         = sizeof(RamDiscardManagerClass),
39468d7f2e76SPhilippe Mathieu-Daudé };
39478d7f2e76SPhilippe Mathieu-Daudé 
memory_register_types(void)39488d7f2e76SPhilippe Mathieu-Daudé static void memory_register_types(void)
39498d7f2e76SPhilippe Mathieu-Daudé {
39508d7f2e76SPhilippe Mathieu-Daudé     type_register_static(&memory_region_info);
39518d7f2e76SPhilippe Mathieu-Daudé     type_register_static(&iommu_memory_region_info);
39528d7f2e76SPhilippe Mathieu-Daudé     type_register_static(&ram_discard_manager_info);
39538d7f2e76SPhilippe Mathieu-Daudé }
39548d7f2e76SPhilippe Mathieu-Daudé 
39558d7f2e76SPhilippe Mathieu-Daudé type_init(memory_register_types)
3956