memory: allow memory_region_find() to run on non-root memory regions
memory_region_find() is similar to registering a MemoryListener and checking for the MemoryRegionSections that come from a particular region. There is no reason for this to be limited to a root memory region. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
68f3f65b09
commit
73034e9e08
@ -718,24 +718,34 @@ void memory_region_set_alias_offset(MemoryRegion *mr,
|
|||||||
hwaddr offset);
|
hwaddr offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* memory_region_find: locate a MemoryRegion in an address space
|
* memory_region_find: translate an address/size relative to a
|
||||||
|
* MemoryRegion into a #MemoryRegionSection.
|
||||||
*
|
*
|
||||||
* Locates the first #MemoryRegion within an address space given by
|
* Locates the first #MemoryRegion within @mr that overlaps the range
|
||||||
* @address_space that overlaps the range given by @addr and @size.
|
* given by @addr and @size.
|
||||||
*
|
*
|
||||||
* Returns a #MemoryRegionSection that describes a contiguous overlap.
|
* Returns a #MemoryRegionSection that describes a contiguous overlap.
|
||||||
* It will have the following characteristics:
|
* It will have the following characteristics:
|
||||||
* .@offset_within_address_space >= @addr
|
|
||||||
* .@offset_within_address_space + .@size <= @addr + @size
|
|
||||||
* .@size = 0 iff no overlap was found
|
* .@size = 0 iff no overlap was found
|
||||||
* .@mr is non-%NULL iff an overlap was found
|
* .@mr is non-%NULL iff an overlap was found
|
||||||
*
|
*
|
||||||
* @address_space: a top-level (i.e. parentless) region that contains
|
* Remember that in the return value the @offset_within_region is
|
||||||
* the region to be found
|
* relative to the returned region (in the .@mr field), not to the
|
||||||
* @addr: start of the area within @address_space to be searched
|
* @mr argument.
|
||||||
|
*
|
||||||
|
* Similarly, the .@offset_within_address_space is relative to the
|
||||||
|
* address space that contains both regions, the passed and the
|
||||||
|
* returned one. However, in the special case where the @mr argument
|
||||||
|
* has no parent (and thus is the root of the address space), the
|
||||||
|
* following will hold:
|
||||||
|
* .@offset_within_address_space >= @addr
|
||||||
|
* .@offset_within_address_space + .@size <= @addr + @size
|
||||||
|
*
|
||||||
|
* @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
|
* @size: size of the area to be searched
|
||||||
*/
|
*/
|
||||||
MemoryRegionSection memory_region_find(MemoryRegion *address_space,
|
MemoryRegionSection memory_region_find(MemoryRegion *mr,
|
||||||
hwaddr addr, uint64_t size);
|
hwaddr addr, uint64_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
20
memory.c
20
memory.c
@ -1451,15 +1451,24 @@ static FlatRange *address_space_lookup(AddressSpace *as, AddrRange addr)
|
|||||||
sizeof(FlatRange), cmp_flatrange_addr);
|
sizeof(FlatRange), cmp_flatrange_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryRegionSection memory_region_find(MemoryRegion *address_space,
|
MemoryRegionSection memory_region_find(MemoryRegion *mr,
|
||||||
hwaddr addr, uint64_t size)
|
hwaddr addr, uint64_t size)
|
||||||
{
|
{
|
||||||
AddressSpace *as = memory_region_to_address_space(address_space);
|
|
||||||
AddrRange range = addrrange_make(int128_make64(addr),
|
|
||||||
int128_make64(size));
|
|
||||||
FlatRange *fr = address_space_lookup(as, range);
|
|
||||||
MemoryRegionSection ret = { .mr = NULL, .size = 0 };
|
MemoryRegionSection ret = { .mr = NULL, .size = 0 };
|
||||||
|
MemoryRegion *root;
|
||||||
|
AddressSpace *as;
|
||||||
|
AddrRange range;
|
||||||
|
FlatRange *fr;
|
||||||
|
|
||||||
|
addr += mr->addr;
|
||||||
|
for (root = mr; root->parent; ) {
|
||||||
|
root = root->parent;
|
||||||
|
addr += root->addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
as = memory_region_to_address_space(root);
|
||||||
|
range = addrrange_make(int128_make64(addr), int128_make64(size));
|
||||||
|
fr = address_space_lookup(as, range);
|
||||||
if (!fr) {
|
if (!fr) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1470,6 +1479,7 @@ MemoryRegionSection memory_region_find(MemoryRegion *address_space,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret.mr = fr->mr;
|
ret.mr = fr->mr;
|
||||||
|
ret.address_space = as;
|
||||||
range = addrrange_intersection(range, fr->addr);
|
range = addrrange_intersection(range, fr->addr);
|
||||||
ret.offset_within_region = fr->offset_in_region;
|
ret.offset_within_region = fr->offset_in_region;
|
||||||
ret.offset_within_region += int128_get64(int128_sub(range.start,
|
ret.offset_within_region += int128_get64(int128_sub(range.start,
|
||||||
|
Loading…
Reference in New Issue
Block a user