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) {
__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));
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));
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)));
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;
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);
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