acpi: Backout changes to acpica_osglue code.
authorSimon Gerber <simon.gerber@inf.ethz.ch>
Thu, 15 Dec 2016 15:29:17 +0000 (16:29 +0100)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Thu, 15 Dec 2016 15:46:31 +0000 (16:46 +0100)
This partially reverts commits b1ce23ccd6ee352cea33d0bd3dd57d16cf75ab23 and
6e794c94b0588b3e9648c9b62575481a8b5b5c51.

Signed-off-by: Simon Gerber <simon.gerber@inf.ethz.ch>

usr/acpi/acpica_osglue.c

index 6f8c5dd..0f89a21 100644 (file)
@@ -550,6 +550,9 @@ AcpiOsMapMemory (
 
     ACPI_DEBUG("AcpiOsMapMemory: aligned request: 0x%"PRIxLPADDR", %d\n", pbase, npages);
 
+    struct capref am_pages[npages];
+    memset(&am_pages, 0, npages*sizeof(struct capref));
+
     for (struct AcpiMapping *walk = head; walk; walk = walk->next) {
         lpaddr_t walk_end = walk->pbase + walk->length;
         if (walk->pbase <= pbase && walk_end >= pend) {
@@ -558,6 +561,47 @@ AcpiOsMapMemory (
                     __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];
+            }
+        }
+        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];
+            }
+        }
+        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];
+            }
+        }
     }
 
     struct memobj_anon *memobj = malloc(sizeof(struct memobj_anon));
@@ -575,6 +619,8 @@ AcpiOsMapMemory (
         DEBUG_ERR(err, "vregion_map failed");
         return NULL;
     }
+    ACPI_DEBUG("%s: Mapping %#"PRIxLPADDR" at %#"PRIxGENVADDR"\n",
+            __FUNCTION__, pbase, vregion_get_base_addr(vregion));
 
     ACPI_DEBUG("%s: Mapping %#"PRIxLPADDR" at %#"PRIxGENVADDR"\n",
             __FUNCTION__, pbase, vregion_get_base_addr(vregion));
@@ -583,29 +629,44 @@ AcpiOsMapMemory (
     new->num_caps = npages;
     new->caps = calloc(npages, sizeof(struct capref));
     for (int page = 0; page < npages; page++) {
-
-        // Always mm_realloc_range() all pages, because this will allow
-        // AcpiOsUnmapMemory to always call mm_free() on all pages and the MM
-        // refcounting will take care of making sure we do not mark regions
-        // free too early.
+        struct capref frame_cap;
         lpaddr_t paddr = pbase + page * BASE_PAGE_SIZE;
 
-        ACPI_DEBUG("%s: allocating page for %#"PRIxLPADDR"\n",
-                __FUNCTION__, paddr);
+        if (capref_is_null(am_pages[page])) {
+            ACPI_DEBUG("%s: allocating page for %#"PRIxLPADDR"\n",
+                    __FUNCTION__, paddr);
+
+            err = mm_realloc_range(&pci_mm_physaddr, BASE_PAGE_BITS, paddr,
+                                   &frame_cap);
+            if (err_is_fail(err)) {
+                free(new->caps);
+                free(new);
+                DEBUG_ERR(err, "AcpiOsMapMemory: allocating RAM at %lx failed\n",
+                          paddr);
+                return NULL;
+            }
+            /* result of mm_realloc_range is already DevFrame */
+        }
+        else {
+            ACPI_DEBUG("%s: using existing page for %#"PRIxLPADDR"\n",
+                    __FUNCTION__, paddr);
+            frame_cap = am_pages[page];
+        }
 
-        err = mm_realloc_range(&pci_mm_physaddr, BASE_PAGE_BITS, paddr,
-                &new->caps[page]);
+        err = slot_alloc(&new->caps[page]);
         if (err_is_fail(err)) {
-            free(new->caps);
-            free(new);
-            DEBUG_ERR(err, "AcpiOsMapMemory: allocating RAM at %lx failed\n",
-                    paddr);
+            DEBUG_ERR(err, "AcpiOsMapMemory: could not allocate slot for capability: %s.",
+                    err_getstring(err_no(err)));
+            return NULL;
+        }
+        err = cap_copy(new->caps[page], frame_cap);
+        if (err_is_fail(err)) {
+            DEBUG_ERR(err, "AcpiOsMapMemory: cap_copy failed: %s.",
+                    err_getstring(err_no(err)));
             return NULL;
         }
-        /* result of mm_realloc_range is already DevFrame */
-
         err = memobj->m.f.fill(&memobj->m, page * BASE_PAGE_SIZE, new->caps[page],
-                BASE_PAGE_SIZE);
+                           BASE_PAGE_SIZE);
         if (err_is_fail(err)) {
             DEBUG_ERR(err, "AcpiOsMapMemory: memobj fill failed: %s.",
                     err_getstring(err_no(err)));
@@ -667,7 +728,6 @@ AcpiOsUnmapMemory (
     assert(head); // there should be a mapped region if Unmap is called
 
     struct AcpiMapping *prev = NULL;
-    errval_t err;
     for (struct AcpiMapping *walk = head; walk; prev = walk, walk = walk->next) {
         genvaddr_t walk_vaddr = vregion_get_base_addr(walk->vregion);
         genvaddr_t walk_end   = walk_vaddr + walk->length;
@@ -677,21 +737,14 @@ AcpiOsUnmapMemory (
             walk->refcount--;
             if (!walk->refcount) {
                 ACPI_DEBUG("%s: last reference to region, cleaning up\n", __FUNCTION__);
-
-                // Remove from list
-                if (prev) {
-                    prev->next = walk->next;
-                }
-                else { // we were head
-                    head = walk->next;
-                }
-
+                errval_t err;
                 // Delete vregion; do this first because vnode_unmap complains
                 // about missing caps if we mm_free() the backing caps first
                 err = vregion_destroy(walk->vregion);
                 if (err_is_fail(err)) {
                     DEBUG_ERR(err, "%s: vregion_destroy", __FUNCTION__);
                 }
+
                 // Destroy memobj without destroying caps, as we've passed
                 // uncopied caps from MM to memobj->fill().
                 err = memobj_destroy_anon((struct memobj *)walk->memobj, false);
@@ -699,14 +752,17 @@ AcpiOsUnmapMemory (
                     DEBUG_ERR(err, "%s: memobj_destroy_anon", __FUNCTION__);
                 }
 
-                // return backing caps to MM
-                for (int page = 0; page < walk->num_caps; page++) {
-                    lpaddr_t pagebase = walk->pbase + page * BASE_PAGE_SIZE;
-                    err = mm_free(&pci_mm_physaddr, walk->caps[page],
-                            pagebase, BASE_PAGE_BITS);
-                    if (err_is_fail(err)) {
-                        DEBUG_ERR(err, "mm_free()");
-                    }
+                // Remove from list
+                if (prev) {
+                    prev->next = walk->next;
+                }
+                else { // we were head
+                    head = walk->next;
+                }
+
+                for (int i = 0; i < walk->num_caps; i++) {
+                    // XXX: ensure that this never deletes a last copy?
+                    cap_destroy(walk->caps[i]);
                 }
 
                 // Free malloc'd memory for element