From: Igor Kotrasinski <i.kotrasi...@partner.samsung.com> Given an address this lets us find the largest contiguous memory range at that address.
Signed-off-by: Igor Kotrasinski <i.kotrasi...@partner.samsung.com> --- include/exec/memory.h | 19 +++++++++++++ memory.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index e85b7de..ac09221 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1915,6 +1915,25 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr, hwaddr addr, uint64_t size); /** + * memory_region_find_flat_range: translate an address/size relative to + * a MemoryRegion into a FlatRange containing it. + * + * Returns a #MemoryRegionSection that describes this FlatRange. + * It will have the following characteristics: + * - @size = 0 iff no containing FlatRange was found + * - @mr is non-%NULL iff a containing FlatRange was found + * + * Remember that in the return value the @offset_within_region is + * relative to the returned region (in the .@mr field), not to the + * @mr argument. + * + * @mr: a MemoryRegion within which @addr is a relative address + * @addr: start of the area within @as to be searched + * @size: size of the area to be searched + */ +MemoryRegionSection memory_region_find_flat_range(MemoryRegion *mr, + hwaddr addr, uint64_t size); +/** * memory_global_dirty_log_sync: synchronize the dirty log for all memory * * Synchronizes the dirty page log for all address spaces. diff --git a/memory.c b/memory.c index aeaa8dc..e9f37e7 100644 --- a/memory.c +++ b/memory.c @@ -2523,6 +2523,25 @@ static FlatRange *flatview_lookup(FlatView *view, AddrRange addr) sizeof(FlatRange), cmp_flatrange_addr); } +static int cmp_flatrange_addr_containing(const void *addr_, const void *fr_) +{ + const AddrRange *addr = addr_; + const FlatRange *fr = fr_; + + if (int128_le(addr->start, fr->addr.start)) { + return -1; + } else if (int128_ge(addrrange_end(*addr), addrrange_end(fr->addr))) { + return 1; + } + return 0; +} + +static FlatRange *flatview_lookup_containing(FlatView *view, AddrRange addr) +{ + return bsearch(&addr, view->ranges, view->nr, + sizeof(FlatRange), cmp_flatrange_addr_containing); +} + bool memory_region_is_mapped(MemoryRegion *mr) { return mr->container ? true : false; @@ -2532,7 +2551,8 @@ bool memory_region_is_mapped(MemoryRegion *mr) * returned region. It must be called from an RCU critical section. */ static MemoryRegionSection memory_region_find_rcu(MemoryRegion *mr, - hwaddr addr, uint64_t size) + hwaddr addr, + uint64_t size) { MemoryRegionSection ret = { .mr = NULL }; MemoryRegion *root; @@ -2576,6 +2596,50 @@ static MemoryRegionSection memory_region_find_rcu(MemoryRegion *mr, return ret; } +/* + * Same as memory_region_find_flat_range, but it does not add a reference to + * the returned region. It must be called from an RCU critical section. + */ +static MemoryRegionSection memory_region_find_flat_range_rcu(MemoryRegion *mr, + hwaddr addr, + uint64_t size) +{ + MemoryRegionSection ret = { .mr = NULL, .size = 0 }; + MemoryRegion *root; + AddressSpace *as; + AddrRange range; + FlatView *view; + FlatRange *fr; + + addr += mr->addr; + for (root = mr; root->container; ) { + root = root->container; + addr += root->addr; + } + + as = memory_region_to_address_space(root); + if (!as) { + return ret; + } + range = addrrange_make(int128_make64(addr), int128_make64(size)); + + view = address_space_to_flatview(as); + fr = flatview_lookup_containing(view, range); + if (!fr) { + return ret; + } + + ret.mr = fr->mr; + ret.fv = view; + range = fr->addr; + ret.offset_within_region = fr->offset_in_region; + ret.size = range.size; + ret.offset_within_address_space = int128_get64(range.start); + ret.readonly = fr->readonly; + ret.nonvolatile = fr->nonvolatile; + return ret; +} + MemoryRegionSection memory_region_find(MemoryRegion *mr, hwaddr addr, uint64_t size) { @@ -2588,6 +2652,19 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr, return ret; } +MemoryRegionSection memory_region_find_flat_range(MemoryRegion *mr, + hwaddr addr, uint64_t size) +{ + MemoryRegionSection ret; + rcu_read_lock(); + ret = memory_region_find_flat_range_rcu(mr, addr, size); + if (ret.mr) { + memory_region_ref(ret.mr); + } + rcu_read_unlock(); + return ret; +} + bool memory_region_present(MemoryRegion *container, hwaddr addr) { MemoryRegion *mr; -- 2.7.4