On 12/19/2011 08:13 AM, Avi Kivity wrote:
Given an address space (represented by the top-level memory region),
returns the memory region that maps a given range.  Useful for implementing
DMA.

The implementation is a simplistic binary search.  Once we have a tree
representation this can be optimized.

Signed-off-by: Avi Kivity<a...@redhat.com>
---
  memory.c |   62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  memory.h |   32 ++++++++++++++++++++++++++++++++
  2 files changed, 94 insertions(+), 0 deletions(-)

diff --git a/memory.c b/memory.c
index cbd6988..d8b7c27 100644
--- a/memory.c
+++ b/memory.c
@@ -514,6 +514,20 @@ static void as_io_ioeventfd_del(AddressSpace *as, 
MemoryRegionIoeventfd *fd)
      .ops =&address_space_ops_io,
  };

+static AddressSpace *memory_region_to_address_space(MemoryRegion *mr)
+{
+    while (mr->parent) {
+        mr = mr->parent;
+    }
+    if (mr == address_space_memory.root) {
+        return&address_space_memory;
+    }
+    if (mr == address_space_io.root) {
+        return&address_space_io;
+    }
+    abort();
+}
+
  /* Render a memory region into the global view.  Ranges in @view obscure
   * ranges in @mr.
   */
@@ -1309,6 +1323,54 @@ void memory_region_del_subregion(MemoryRegion *mr,
      memory_region_update_topology();
  }

+static int cmp_flatrange_addr(const void *_addr, const void *_fr)
+{
+    const AddrRange *addr = _addr;
+    const FlatRange *fr = _fr;

Please don't prefix with an underscore.

+
+    if (int128_le(addrrange_end(*addr), fr->addr.start)) {
+        return -1;
+    } else if (int128_ge(addr->start, addrrange_end(fr->addr))) {
+        return 1;
+    }
+    return 0;
+}
+
+static FlatRange *address_space_lookup(AddressSpace *as, AddrRange addr)
+{
+    return bsearch(&addr, as->current_map.ranges, as->current_map.nr,
+                   sizeof(FlatRange), cmp_flatrange_addr);
+}
+
+MemoryRegionSection memory_region_find(MemoryRegion *address_space,
+                                       target_phys_addr_t 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 };
+
+    if (!fr) {
+        return ret;
+    }
+
+    while (fr>  as->current_map.ranges
+&&  addrrange_intersects(fr[-1].addr, range)) {
+        --fr;
+    }
+
+    ret.mr = fr->mr;
+    range = addrrange_intersection(range, fr->addr);
+    ret.offset_within_region = fr->offset_in_region;
+    ret.offset_within_region += int128_get64(int128_sub(range.start,
+                                                        fr->addr.start));
+    ret.size = int128_get64(range.size);
+    ret.offset_within_address_space = int128_get64(range.start);
+    return ret;
+}
+
+
  void set_system_memory_map(MemoryRegion *mr)
  {
      address_space_memory.root = mr;
diff --git a/memory.h b/memory.h
index beae127..1d5c414 100644
--- a/memory.h
+++ b/memory.h
@@ -146,6 +146,24 @@ struct MemoryRegionPortio {

  #define PORTIO_END_OF_LIST() { }

+typedef struct MemoryRegionSection MemoryRegionSection;
+
+/**
+ * MemoryRegionSection: describes a fragment of a #MemoryRegion
+ *
+ * @mr: the region, or %NULL if empty
+ * @offset_within_region: the beginning of the section, relative to @mr's start
+ * @size: the size of the section; will not exceed @mr's boundaries
+ * @offset_within_address_space: the address of the first byte of the section
+ *     relative to the region's address space
+ */
+struct MemoryRegionSection {
+    MemoryRegion *mr;
+    target_phys_addr_t offset_within_region;
+    uint64_t size;
+    target_phys_addr_t offset_within_address_space;
+};
+
  /**
   * memory_region_init: Initialize a memory region
   *
@@ -502,6 +520,20 @@ void memory_region_del_subregion(MemoryRegion *mr,
                                   MemoryRegion *subregion);

  /**
+ * memory_region_find: locate a MemoryRegion in an address space
+ *
+ * Locates the first #MemoryRegion within an address space given by
+ * @address_space that overlaps the range given by @addr and @size.
+ *
+ * @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
+ * @size: size of the area to be searched
+ */
+MemoryRegionSection memory_region_find(MemoryRegion *address_space,
+                                       target_phys_addr_t addr, uint64_t size);

Returning structs by value is a bit unexpected.

Otherwise, the patch looks good.

Regards,

Anthony Liguori

+
+/**
   * memory_region_transaction_begin: Start a transaction.
   *
   * During a transaction, changes will be accumulated and made visible

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to