Merge large page support code.
[barrelfish] / lib / barrelfish / vspace / memobj_anon.c
index 5e6921b..56e3fc6 100644 (file)
 
 /*
  * Copyright (c) 2009, 2010, 2011, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
  * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
  */
 
 #include <barrelfish/barrelfish.h>
 #include "vspace_internal.h"
-#include <stdio.h>
 
 /**
  * \brief Map the memory object into a region
@@ -42,14 +42,12 @@ static errval_t map_region(struct memobj *memobj, struct vregion *vregion)
         void *buf;
         err = vspace_pinned_alloc(&buf, VREGION_LIST);
         if (err_is_fail(err)) {
-               printf("vspace pinned alloc fail!\n");
             return err_push(err, LIB_ERR_VSPACE_PINNED_ALLOC);
         }
         slab_grow(&anon->vregion_slab, buf,
                   VSPACE_PINNED_UNIT * sizeof(struct vregion_list));
         data = slab_alloc(&anon->vregion_slab);
         if (!data) {
-               printf("slab alloc fail!\n");
             return LIB_ERR_SLAB_ALLOC_FAIL;
         }
     }
@@ -79,30 +77,54 @@ static errval_t unmap_region(struct memobj *memobj, struct vregion *vregion)
     struct pmap *pmap     = vspace_get_pmap(vspace);
     genvaddr_t vregion_base  = vregion_get_base_addr(vregion);
     genvaddr_t vregion_off   = vregion_get_offset(vregion);
+    size_t vregion_size = vregion_get_size(vregion);
+    genvaddr_t vregion_end = vregion_off + vregion_size;
 
-    err = pmap->f.unmap(pmap, vregion_base + vregion_off, memobj->size, NULL);
-    if (err_is_fail(err)) {
-        return err_push(err, LIB_ERR_PMAP_UNMAP);
-    }
+    //printf("(%s:%d) unmap(0x%"PRIxGENVADDR", memobj->size = %zd) vregion size = %zd\n", __FILE__, __LINE__, vregion_base + vregion_off, memobj->size, vregion_size);
 
-    /* Remove the vregion from the list */
-    struct vregion_list *prev = NULL;
-    for (struct vregion_list *elt = anon->vregion_list; elt != NULL;
-         elt = elt->next) {
-        if (elt->region == vregion) {
-            if (prev == NULL) {
-                assert(elt == anon->vregion_list);
-                anon->vregion_list = elt->next;
-            } else {
-                assert(prev->next == elt);
-                prev->next = elt->next;
+    // unmap all affected frames
+    struct memobj_frame_list *fwalk = anon->frame_list;
+    struct memobj_frame_list *fprev = NULL;
+    //printf("vregion_off = 0x%"PRIxGENVADDR"\n", vregion_off);
+    //printf("vregion_end = 0x%"PRIxGENVADDR"\n", vregion_end);
+    err = LIB_ERR_VSPACE_VREGION_NOT_FOUND;
+    while (fwalk) {
+        //printf("fwalk->offset = %zd\n", fwalk->offset);
+        //printf("fwalk->next   = %p\n", fwalk->next);
+        if (fwalk->offset < vregion_off) {
+            fprev = fwalk;
+            fwalk = fwalk->next;
+            continue;
+        }
+        else if (fwalk->offset < vregion_end) {
+            err = pmap->f.unmap(pmap, vregion_base + vregion_off, fwalk->size, NULL);
+            if (err_is_fail(err)) {
+                return err_push(err, LIB_ERR_PMAP_UNMAP);
             }
-            slab_free(&anon->vregion_slab, elt);
-            return SYS_ERR_OK;
+
+            /* Remove the vregion from the list */
+            struct vregion_list *prev = NULL;
+            for (struct vregion_list *elt = anon->vregion_list; elt != NULL;
+                 elt = elt->next) {
+                if (elt->region == vregion) {
+                    if (prev == NULL) {
+                        assert(elt == anon->vregion_list);
+                        anon->vregion_list = elt->next;
+                    } else {
+                        assert(prev->next == elt);
+                        prev->next = elt->next;
+                    }
+                    slab_free(&anon->vregion_slab, elt);
+                    err = SYS_ERR_OK;
+                }
+            }
+            vregion_off += fwalk->size;
+            fprev = fwalk;
+            fwalk = fwalk->next;
         }
     }
 
-    return LIB_ERR_VSPACE_VREGION_NOT_FOUND; // XXX: not quite the right error
+    return err; // XXX: not quite the right error
 }
 
 /**
@@ -170,8 +192,8 @@ static errval_t unpin(struct memobj *memobj, struct vregion *vregion,
  *
  * Pagefault relies on frames inserted in order
  */
-static errval_t fill(struct memobj *memobj, genvaddr_t offset, struct capref frame,
-                     size_t size)
+static errval_t fill_foff(struct memobj *memobj, genvaddr_t offset, struct capref frame,
+                     size_t size, genpaddr_t foffset)
 {
     errval_t err;
     struct memobj_anon *anon = (struct memobj_anon*)memobj;
@@ -199,9 +221,17 @@ static errval_t fill(struct memobj *memobj, genvaddr_t offset, struct capref fra
             return LIB_ERR_SLAB_ALLOC_FAIL;
         }
     }
-    new->offset = offset;
-    new->frame  = frame;
-    new->size   = size;
+    new->offset  = offset;
+    new->frame   = frame;
+    new->size    = size;
+    new->foffset = foffset;
+
+    {
+        struct frame_identity id;
+        err = invoke_frame_identify(frame, &id);
+        assert(err_is_ok(err));
+        new->pa = id.base;
+    }
 
     // Insert in order
     struct memobj_frame_list *walk = anon->frame_list;
@@ -239,6 +269,11 @@ static errval_t fill(struct memobj *memobj, genvaddr_t offset, struct capref fra
     }
     return SYS_ERR_OK;
 }
+static errval_t fill(struct memobj *memobj, genvaddr_t offset, struct capref frame,
+                     size_t size)
+{
+    return fill_foff(memobj, offset, frame, size, 0);
+}
 
 /**
  * \brief Unmap/remove one frame from the end of the memobj
@@ -283,6 +318,7 @@ static errval_t unfill(struct memobj *memobj, genvaddr_t offset,
             size_t retsize;
 
             assert((vregion_base + fwalk->offset) % BASE_PAGE_SIZE == 0);
+            //printf("(%s:%d) unmap(0x%"PRIxGENVADDR", %zd)\n", __FILE__, __LINE__, vregion_base + fwalk->offset, fwalk->size);
             err = pmap->f.unmap(pmap, vregion_base + fwalk->offset, fwalk->size,
                                 &retsize);
             if (err_is_fail(err)) {
@@ -294,8 +330,12 @@ static errval_t unfill(struct memobj *memobj, genvaddr_t offset,
     }
 
     // Return the frame
-    *ret_offset = fwalk->offset;
-    *ret_frame = fwalk->frame;
+    if (ret_offset) {
+        *ret_offset = fwalk->offset;
+    }
+    if (ret_frame) {
+        *ret_frame = fwalk->frame;
+    }
     if (fprev) {
         fprev->next = fwalk->next;
     } else {
@@ -332,7 +372,8 @@ static errval_t pagefault(struct memobj *memobj, struct vregion *vregion,
             genvaddr_t vregion_off   = vregion_get_offset(vregion);
             vregion_flags_t flags = vregion_get_flags(vregion);
             err = pmap->f.map(pmap, base + vregion_off + walk->offset,
-                              walk->frame, 0, walk->size, flags, NULL, NULL);
+                              walk->frame, walk->foffset, walk->size, flags,
+                              NULL, NULL);
             if (err_is_fail(err)) {
                 return err_push(err, LIB_ERR_PMAP_MAP);
             }
@@ -382,6 +423,7 @@ errval_t memobj_create_anon(struct memobj_anon *anon, size_t size,
     memobj->f.pin          = pin;
     memobj->f.unpin        = unpin;
     memobj->f.fill         = fill;
+    memobj->f.fill_foff    = fill_foff;
     memobj->f.unfill       = unfill;
     memobj->f.pagefault    = pagefault;
     memobj->f.pager_free   = pager_free;
@@ -403,9 +445,33 @@ errval_t memobj_create_anon(struct memobj_anon *anon, size_t size,
 /**
  * \brief Destroy the object
  *
- * \bug NYI
  */
 errval_t memobj_destroy_anon(struct memobj *memobj)
 {
-    return SYS_ERR_OK;
+    struct memobj_anon *m = (struct memobj_anon *)memobj;
+
+    errval_t err = SYS_ERR_OK;
+
+    struct vregion_list *vwalk = m->vregion_list;
+    while (vwalk) {
+        err = vregion_destroy(vwalk->region);
+        if (err_is_fail(err)) {
+            return err;
+        }
+        struct vregion_list *old = vwalk;
+        vwalk = vwalk->next;
+        slab_free(&m->vregion_slab, old);
+    }
+
+    struct memobj_frame_list *fwalk = m->frame_list;
+    while (fwalk) {
+        err = cap_delete(fwalk->frame);
+        if (err_is_fail(err)) {
+            return err;
+        }
+        struct memobj_frame_list *old = fwalk;
+        fwalk = fwalk->next;
+        slab_free(&m->frame_slab, old);
+    }
+    return err;
 }