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);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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
 | 
			
		||||
 * @address_space that overlaps the range given by @addr and @size.
 | 
			
		||||
 * Locates the first #MemoryRegion within @mr that overlaps the range
 | 
			
		||||
 * given by @addr and @size.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns a #MemoryRegionSection that describes a contiguous overlap.
 | 
			
		||||
 * 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
 | 
			
		||||
 *    .@mr is non-%NULL iff an overlap was found
 | 
			
		||||
 *
 | 
			
		||||
 * @address_space: a top-level (i.e. parentless) region that contains
 | 
			
		||||
 *       the region to be found
 | 
			
		||||
 * @addr: start of the area within @address_space to be searched
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 */
 | 
			
		||||
MemoryRegionSection memory_region_find(MemoryRegion *address_space,
 | 
			
		||||
MemoryRegionSection memory_region_find(MemoryRegion *mr,
 | 
			
		||||
                                       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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MemoryRegionSection memory_region_find(MemoryRegion *address_space,
 | 
			
		||||
MemoryRegionSection memory_region_find(MemoryRegion *mr,
 | 
			
		||||
                                       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 };
 | 
			
		||||
    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) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1470,6 +1479,7 @@ MemoryRegionSection memory_region_find(MemoryRegion *address_space,
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    ret.mr = fr->mr;
 | 
			
		||||
    ret.address_space = as;
 | 
			
		||||
    range = addrrange_intersection(range, fr->addr);
 | 
			
		||||
    ret.offset_within_region = fr->offset_in_region;
 | 
			
		||||
    ret.offset_within_region += int128_get64(int128_sub(range.start,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue