ACPI: fixing table mapping code
authorReto Achermann <reto.achermann@inf.ethz.ch>
Wed, 15 Mar 2017 17:45:37 +0000 (18:45 +0100)
committerReto Achermann <reto.achermann@inf.ethz.ch>
Wed, 15 Mar 2017 17:45:37 +0000 (18:45 +0100)
Signed-off-by: Reto Achermann <reto.achermann@inf.ethz.ch>

usr/acpi/acpica_osglue.c

index 0f89a21..1f95961 100644 (file)
@@ -539,67 +539,125 @@ AcpiOsMapMemory (
     ACPI_PHYSICAL_ADDRESS   where,  /* not page aligned */
     ACPI_SIZE               length) /* in bytes, not page-aligned */
 {
-    ACPI_DEBUG("AcpiOsMapMemory where=0x%016lx, length=%lu\n", where, length);
     errval_t err;
+
+    ACPI_DEBUG("AcpiOsMapMemory where=0x%016lx, length=%lu\n", where, length);
+
     //printf("AcpiOsMapMemory: 0x%"PRIxLPADDR", %lu\n", where, length);
+
+    /* round the addresses to page boundary */
     lpaddr_t pbase = where & (~BASE_PAGE_MASK);
     length += where - pbase;
     length = ROUND_UP(length, BASE_PAGE_SIZE);
-    int npages = DIVIDE_ROUND_UP(length, BASE_PAGE_SIZE);
-    lpaddr_t pend  = pbase + length;
+    size_t npages = DIVIDE_ROUND_UP(length, BASE_PAGE_SIZE);
+
+    lpaddr_t pend  = pbase + length - 1;
 
-    ACPI_DEBUG("AcpiOsMapMemory: aligned request: 0x%"PRIxLPADDR", %d\n", pbase, npages);
+    ACPI_DEBUG("AcpiOsMapMemory: aligned request: 0x%" PRIxLPADDR "..0x%"
+                PRIxLPADDR", %d\n", pbase, pend, npages);
 
     struct capref am_pages[npages];
     memset(&am_pages, 0, npages*sizeof(struct capref));
 
+    /* find existing mappings */
     for (struct AcpiMapping *walk = head; walk; walk = walk->next) {
-        lpaddr_t walk_end = walk->pbase + walk->length;
-        if (walk->pbase <= pbase && walk_end >= pend) {
-            walk->refcount++;
-            ACPI_DEBUG("%s: found region for request (new refcount=%d), mapped at %#"PRIxLVADDR"\n",
-                    __FUNCTION__, walk->refcount, vregion_get_base_addr(walk->vregion));
-            return (void*)(uintptr_t)vregion_get_base_addr(walk->vregion) + (where-walk->pbase);
-        }
-        // overlapping map requests
-        else if (walk->pbase >= pbase && walk_end <= pend) {
-            //printf("old mapping inside request\n");
-            // new request contains old mapping
-            //        |---| walk
-            // |---------------| new mapping
-            size_t first = (walk->pbase - pbase) / BASE_PAGE_SIZE;
-            // printf("pbase = 0x%"PRIxGENPADDR", walk->pbase = 0x%"PRIxGENPADDR"\n", pbase, walk->pbase);
-            // printf("npages = %d, walk->npages = %zd\n", npages, walk->num_caps);
-            // printf("caps %zd - %zd already retyped\n", first, first + walk->num_caps-1);
-            for (int c = 0; c < walk->num_caps; c++) {
-                am_pages[first + c] = walk->caps[c];
+        lpaddr_t walk_end = walk->pbase + walk->length - 1;
+
+        ACPI_DEBUG("%s: walk=0x%" PRIxLPADDR "...0x%" PRIxLPADDR ", region=0x%"
+                   PRIxLPADDR "...0x%" PRIxLPADDR "\n", __FUNCTION__,
+                   walk->pbase, walk_end, pbase, pend);
+
+        /*
+         * The walk region starts before the requested region.
+         *   Walk   |------------------
+         *   Region         |-----------------
+         */
+        if (walk->pbase <= pbase) {
+
+            /*
+             * The walk region ends after the requested region.
+             *   Walk   |------------------|
+             *   Region         |--------|
+             *
+             *   We have found the overlapping region, return this.
+             *   Increase the refcount and return
+             */
+            if (walk_end >= pend) {
+                walk->refcount++;
+                ACPI_DEBUG("%s: found region for request (new refcount=%d), "
+                           "mapped at %#"PRIxLVADDR"\n", __FUNCTION__,
+                           walk->refcount, vregion_get_base_addr(walk->vregion));
+
+                return (void*)(uintptr_t)vregion_get_base_addr(walk->vregion)
+                                                   + (where-walk->pbase);
             }
-        }
-        else if (walk->pbase < pbase && walk_end > pbase && walk_end < pend) {
-            //printf("old mapping at beginning of new request\n");
-            // new request overlaps end of old mapping-->walk_end < pend
-            // |--------| walk
-            //       |--------------| new mapping
-            size_t overlap_count = (walk_end - pbase) / BASE_PAGE_SIZE;
-            //printf("pbase = 0x%"PRIxGENPADDR", walk->pbase = 0x%"PRIxGENPADDR"\n", pbase, walk->pbase);
-            //printf("npages = %d, walk->npages = %zd\n", npages, walk->num_caps);
-            //printf("caps %d - %zd already retyped\n", 0, overlap_count - 1);
-            for (int c = 0; c < overlap_count; c++) {
-                am_pages[c] = walk->caps[walk->num_caps - overlap_count + c];
+
+            /*
+             * The walk region ends before the requested region.
+             *   Walk   |----|
+             *   Region         |--------|
+             *
+             *   We have found the overlapping region, return this.
+             *   Increase the refcount and return
+             */
+
+            if (walk_end < pbase) {
+                continue;
             }
-        }
-        else if (walk->pbase > pbase && walk->pbase < pend && walk_end > pend) {
-            //printf("old mapping at end of new request\n");
-            // new request overlaps beginning of old mapping
-            //               |-----| walk
-            // |---------------| new mapping
-            size_t first = (pend - walk->pbase) / BASE_PAGE_SIZE;
-            size_t overlap_count = npages - first;
-            //printf("pbase = 0x%"PRIxGENPADDR", walk->pbase = 0x%"PRIxGENPADDR"\n", pbase, walk->pbase);
-            //printf("npages = %d, walk->npages = %zd\n", npages, walk->num_caps);
-            //printf("caps %zd - %zd already retyped\n", first, first + overlap_count - 1);
-            for (int c = 0; c < overlap_count; c++) {
-                am_pages[first + c] =  walk->caps[c];
+
+            /*
+             * The walk region ends before the requested region ends
+             *   Walk   |------------------|
+             *   Region         |--------------|
+             *
+             * We can use the caps of the parts of this walk region. From
+             * where the requested region starts until the end.
+             */
+            size_t walk_offset = (walk->pbase - pbase) / BASE_PAGE_SIZE;
+            size_t idx = 0;
+            for (size_t i = walk_offset; i < walk->num_caps; i++) {
+                ACPI_DEBUG("%s: using am_pages[%zu/%zu] = walk->caps[%zu/%zu] with paddr=0x%"
+                           PRIxLPADDR "\n", __FUNCTION__, idx, npages, i,
+                           walk->num_caps,  walk->pbase + i * BASE_PAGE_SIZE);
+                assert(i < walk->num_caps);
+                assert(idx < npages);
+                am_pages[idx++] = walk->caps[i];
+
+
+            }
+        } else {
+
+            /*
+             * The walk region starts after the requested element.
+             *   Walk                |------------------|
+             *   Region   |------|
+             *
+             *   walk->pbase > pbase
+             *
+             *   the region is outside of the walk.
+             */
+            if (walk->pbase > pend) {
+                continue;
+            }
+
+            /*
+             * The walk region starts after the requested element.
+             *   Walk          |------------------|
+             *   Region   |------|
+             *
+             *   walk->pbase > pbase
+             *
+             *   the region is outside of the walk.
+             */
+            size_t region_offset = (walk->pbase - pbase) / BASE_PAGE_SIZE;
+            size_t idx = 0;
+            for (lpaddr_t cur = walk->pbase; cur < pend; cur += BASE_PAGE_SIZE) {
+                ACPI_DEBUG("%s: using am_pages[%zu/%zu] = walk->caps[%zu/%zu] with paddr=0x%"
+                           PRIxLPADDR "\n", __FUNCTION__, region_offset, npages, idx,
+                           walk->num_caps,  walk->pbase + idx * BASE_PAGE_SIZE);
+                assert(region_offset < npages);
+                assert(idx < walk->num_caps);
+                am_pages[region_offset++] = walk->caps[idx++];
             }
         }
     }