Largepage repository
authorAndreas Dillier <dilliera@ethz.ch>
Sun, 1 Dec 2013 23:42:50 +0000 (00:42 +0100)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Thu, 30 Apr 2015 18:10:15 +0000 (20:10 +0200)
Fixing the issue with the repository not having a history

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

12 files changed:
kernel/arch/x86_32/page_mappings_arch.c
kernel/arch/x86_32/startup_arch.c
kernel/arch/x86_64/page_mappings_arch.c
lib/barrelfish/arch/arm/pmap_arch.c
lib/barrelfish/target/x86_32/pmap_target.c
lib/barrelfish/target/x86_64/pmap_target.c
usr/bench/largepage/Hakefile [new file with mode: 0644]
usr/bench/largepage/largepage_64_bench.c [new file with mode: 0644]
usr/vnode_map_32/Hakefile [new file with mode: 0644]
usr/vnode_map_32/vnode_map_32.c [new file with mode: 0644]
usr/vnode_map_test/Hakefile [new file with mode: 0644]
usr/vnode_map_test/vnode_map_test.c [new file with mode: 0644]

index 0b7ebfc..f713acb 100644 (file)
@@ -90,12 +90,11 @@ static errval_t x86_32_pdir(struct capability *dest, cslot_t slot,
     }
 #endif
 
-    //TODO large page code
+    // large page code
     size_t page_size = X86_32_LARGE_PAGE_SIZE;
     if(dest->type == ObjType_VNode_x86_32_pdir &&
        src->type != ObjType_VNode_x86_32_ptable)
     {
-        printf("\tlarge page\n");
         cslot_t last_slot = slot + pte_count;
 
         if (src->type != ObjType_Frame &&
@@ -110,7 +109,6 @@ static errval_t x86_32_pdir(struct capability *dest, cslot_t slot,
             return SYS_ERR_FRAME_OFFSET_INVALID;
         }
 
-        printf("calc new flags\n");
         /* Calculate page access protection flags */
         // Get frame cap rights
         paging_x86_32_flags_t flags_large =
@@ -122,7 +120,6 @@ static errval_t x86_32_pdir(struct capability *dest, cslot_t slot,
         // Unconditionally mark the page present
         flags_large |= X86_32_PTABLE_PRESENT;
     
-        printf("calc addrs\n");
         // Convert destination base address
         genpaddr_t dest_gp   = get_address(dest);
         lpaddr_t dest_lp     = gen_phys_to_local_phys(dest_gp);
@@ -131,16 +128,13 @@ static errval_t x86_32_pdir(struct capability *dest, cslot_t slot,
         genpaddr_t src_gp   = get_address(src);
         lpaddr_t src_lp     = gen_phys_to_local_phys(src_gp);
         // Set metadata
-        printf("set metadata\n");
         struct cte *src_cte = cte_for_cap(src);
         src_cte->mapping_info.pte = dest_lp + slot * sizeof(union x86_32_ptable_entry);
         src_cte->mapping_info.pte_count = pte_count;
         src_cte->mapping_info.offset = offset;
     
 
-        printf("start looping\n");
         for (; slot < last_slot; slot++, offset += page_size) {
-            printf("looping\n");
             union x86_32_ptable_entry *entry =
                 (union x86_32_ptable_entry *)dest_lv + slot;
                 
@@ -152,17 +146,14 @@ static errval_t x86_32_pdir(struct capability *dest, cslot_t slot,
                 return SYS_ERR_VNODE_SLOT_INUSE;
             }
             
-            printf("map it\n");
             // Carry out the page mapping
             paging_x86_32_map_large(entry, src_lp + offset, flags_large);
         }
 
-        printf("mapping complete\n");
         return SYS_ERR_OK;
     }
 
     if (src->type != ObjType_VNode_x86_32_ptable) { // Right mapping
-        printf("error4\n");
         return SYS_ERR_WRONG_MAPPING;
     }
 
@@ -437,7 +428,8 @@ errval_t page_mappings_unmap(struct capability *pgtable, struct cte *mapping, si
     // flush TLB for unmapped pages
     // TODO: heuristic that decides if selective or full flush is more
     //       efficient?
-    if (num_pages > 1) {
+    //       currently set to trivially flush entire tlb to make large page unmapping work
+    if (num_pages > 1 || true) {
         do_full_tlb_flush();
     } else {
         do_one_tlb_flush(vaddr);
index 3bdcdfd..5fe6c3a 100644 (file)
@@ -119,9 +119,9 @@ errval_t startup_map_init(lvaddr_t vbase, lpaddr_t base, size_t size,
                     + X86_32_PDIR_BASE(vaddr) * X86_32_PTABLE_SIZE
                     + X86_32_PTABLE_BASE(vaddr)];
 
-        debug(SUBSYS_PAGING, "Mapping 4K page: vaddr = 0x%"PRIxLVADDR", base = 0x%"PRIxLPADDR", "
-              "PDPTE_BASE = %"PRIuLPADDR", PDIR_BASE = %"PRIuLPADDR", "
-              "PTABLE_BASE = %"PRIuLPADDR" -- ", vaddr, base, X86_32_PDPTE_BASE(vaddr),
+        debug(SUBSYS_PAGING, "Mapping 4K page: vaddr = 0x%x, base = 0x%x, "
+              "PDPTE_BASE = %u, PDIR_BASE = %u, "
+              "PTABLE_BASE = %u -- ", vaddr, base, X86_32_PDPTE_BASE(vaddr),
               X86_32_PDIR_BASE(vaddr), X86_32_PTABLE_BASE(vaddr));
 #else
         union x86_32_ptable_entry *ptable_base = &init_ptable[
index 9cf12f3..d8ead39 100644 (file)
@@ -60,7 +60,7 @@ static errval_t x86_64_non_ptable(struct capability *dest, cslot_t slot,
             }
             break;
         case ObjType_VNode_x86_64_pdpt:
-            // TODO: huge page support, set page_size to HUGE_PAGE_SIZE
+            // huge page support
             if (src->type != ObjType_VNode_x86_64_pdir) { // Right mapping
                 // TODO: check if the system allows 1GB mappings
                 page_size = X86_64_HUGE_PAGE_SIZE;
@@ -84,11 +84,9 @@ static errval_t x86_64_non_ptable(struct capability *dest, cslot_t slot,
             }
             break;
         case ObjType_VNode_x86_64_pdir:
-            // superpage support, set page_size to LARGE_PAGE_SIZE
+            // superpage support
             if (src->type != ObjType_VNode_x86_64_ptable) { // Right mapping
-                printf("2m page ------\n");
-                page_size = X86_64_LARGE_PAGE_SIZE;
-                
+                page_size = X86_64_LARGE_PAGE_SIZE;               
                                 
                 // check offset within frame
                 genpaddr_t off = offset;
@@ -139,6 +137,8 @@ static errval_t x86_64_non_ptable(struct capability *dest, cslot_t slot,
             printf("slot in use\n");
             return SYS_ERR_VNODE_SLOT_INUSE;
         }
+        
+        // determine if we map a large/huge page or a normal entry
         if (page_size == X86_64_LARGE_PAGE_SIZE)
         {  
             //a large page is mapped
index 9ded439..0e2b3d2 100644 (file)
@@ -18,7 +18,7 @@
  * resource bootstrapping. The bootstrap ram allocator allocates pages.
  *
  *
- * The natural division of bits is 12/8/12, corresponding to 4K
+ * The natural division of bits is 12/10/12, corresponding to 4K
  * L1 entries in the L1 table and 256 L2 entries per L2
  * table. Unfortunately 256 entries consumes 1KB rather than a
  * page (4KB) so we pretend here and in the kernel caps page
 #define ARM_USER_L1_OFFSET(addr) ((uintptr_t)(addr >> 22) & 0x3ffu)
 #define ARM_USER_L2_OFFSET(addr) ((uintptr_t)(addr >> 12) & 0x3ffu)
 
-//flag for large page mapping
-#define FLAGS_LARGE 0x0100
+//large mapping flags
+#define FLAGS_LARGE        0x0100
+#define FLAGS_SECTION      0x0200
+#define FLAGS_SUPERSECTION 0x0300
 
 static inline uintptr_t
 vregion_flags_to_kpi_paging_flags(vregion_flags_t flags)
@@ -270,42 +272,6 @@ static errval_t get_ptable(struct pmap_arm  *pmap,
 
     return SYS_ERR_OK;
 }
-/**
- * \brief Returns the vnode for the TODO pdir mapping a given vspace address
- */
-static errval_t get_pdir(struct pmap_arm  *pmap,
-                           genvaddr_t        vaddr,
-                           struct vnode    **ptable)
-{
-    // NB Strictly there are 12 bits in the ARM L1, but allocations unit
-    // of L2 is 1 page of L2 entries (4 tables) so we use 10 bits for the L1
-    // index here
-    uintptr_t index = ARM_USER_L1_OFFSET(vaddr);
-    if ((*ptable = find_vnode(&pmap->root, index)) == NULL)
-    {
-        // L1 table entries point to L2 tables so allocate an L2
-        // table for this L1 entry.
-
-        struct vnode *tmp = NULL; // Tmp variable for passing to alloc_vnode
-
-        errval_t err = alloc_vnode(pmap, &pmap->root, ObjType_VNode_ARM_l2,
-                                   index, &tmp);
-        if (err_is_fail(err)) {
-            DEBUG_ERR(err, "alloc_vnode");
-            return err;
-        }
-        assert(tmp != NULL);
-        *ptable = tmp; // Set argument to received value
-
-
-        if (err_is_fail(err)) {
-            return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
-        }
-    }
-
-    return SYS_ERR_OK;
-}
-
 
 static struct vnode *find_ptable(struct pmap_arm  *pmap,
                                  genvaddr_t vaddr)
@@ -320,29 +286,31 @@ static errval_t do_single_map(struct pmap_arm *pmap, genvaddr_t vaddr, genvaddr_
                               struct capref frame, size_t offset, size_t pte_count,
                               vregion_flags_t flags)
 {
+    errval_t err = SYS_ERR_OK;
     // Get the page table
     struct vnode *ptable;
-    errval_t err;
-    if (flags&FLAGS_LARGE)
-    {
-        //large page mapping
-        err = get_pdir(pmap, vaddr, &ptable);
-        flags &= ~(FLAGS_LARGE);
-    }
-    else
-    {
-        //normal 4k mapping
+    uintptr_t index;
+    if (flags&FLAGS_SECTION) {
+        //section mapping (1MB)
+        //mapped in the L1 table at root
+        ptable = &pmap->root;
+        index = ARM_USER_L1_OFFSET(vaddr);
+        printf("do_single_map: large path\n");
+    } else {
+        //4k mapping
         err = get_ptable(pmap, vaddr, &ptable);
+        index = ARM_USER_L2_OFFSET(vaddr);
     }
     if (err_is_fail(err)) {
         return err_push(err, LIB_ERR_PMAP_GET_PTABLE);
     }
-    uintptr_t pmap_flags = vregion_flags_to_kpi_paging_flags(flags);
+    uintptr_t pmap_flags = vregion_flags_to_kpi_paging_flags(flags&~FLAGS_SUPERSECTION);
     // XXX: reassess the following note -SG
     // NOTE: strictly speaking a l2 entry only has 8 bits, but due to the way
     // Barrelfish allocates l1 and l2 tables, we use 10 bits for the tracking
     // index here and in the map syscall
-    uintptr_t index = ARM_USER_L2_OFFSET(vaddr);
+    // NOTE: index determined in the pagesize branch -AD
+    //uintptr_t index = ARM_USER_L2_OFFSET(vaddr);
     // Create user level datastructure for the mapping
     bool has_page = has_vnode(ptable, index, pte_count);
     assert(!has_page);
@@ -353,6 +321,7 @@ static errval_t do_single_map(struct pmap_arm *pmap, genvaddr_t vaddr, genvaddr_
     page->next  = ptable->u.vnode.children;
     ptable->u.vnode.children = page;
     page->u.frame.cap = frame;
+    page->u.frame.flags = flags;
     page->u.frame.pte_count = pte_count;
 
     // Map entry into the page table
@@ -369,24 +338,28 @@ static errval_t do_map(struct pmap_arm *pmap, genvaddr_t vaddr,
                        vregion_flags_t flags, size_t *retoff, size_t *retsize)
 {
     errval_t err;
-    
     size_t page_size;
-    if (flags&FLAGS_LARGE)
-    {
-        //L2 mapping
-//        page_size = LARGE_PAGE_SIZE;
-    }
-    else
-    {
+    size_t offset_level;
+    // determine mapping specific parts
+    if (flags&FLAGS_SECTION) {
+        //section mapping (1MB)
+        page_size = LARGE_PAGE_SIZE;
+        offset_level = ARM_L1_OFFSET(vaddr);
+        printf("do_map: large path\n");
+        printf("page_size: %i, size: %i\n", page_size, size);
+    } else {
         //normal 4k mapping
         page_size = BASE_PAGE_SIZE;
+        offset_level = ARM_L2_OFFSET(vaddr);
     }
+
     size = ROUND_UP(size, page_size);
     size_t pte_count = DIVIDE_ROUND_UP(size, page_size);
-
     genvaddr_t vend = vaddr + size;
 
-    if (ARM_L1_OFFSET(vaddr) == ARM_L1_OFFSET(vend-1)) {
+    //should be trivially true for section mappings
+    if ((ARM_L1_OFFSET(vaddr) == ARM_L1_OFFSET(vend-1)) ||
+        flags&FLAGS_SECTION) {
         // fast path
         err = do_single_map(pmap, vaddr, vend, frame, offset, pte_count, flags);
         if (err_is_fail(err)) {
@@ -395,7 +368,7 @@ static errval_t do_map(struct pmap_arm *pmap, genvaddr_t vaddr,
         }
     } else { // multiple leaf page tables
         // first leaf
-        uint32_t c = ARM_L2_MAX_ENTRIES - ARM_L2_OFFSET(vaddr);
+        uint32_t c = ARM_L2_MAX_ENTRIES - offset_level;
         genvaddr_t temp_end = vaddr + c * page_size;
         err = do_single_map(pmap, vaddr, temp_end, frame, offset, c, flags);
         if (err_is_fail(err)) {
@@ -487,6 +460,13 @@ max_slabs_required(size_t bytes)
     size_t l1entries = DIVIDE_ROUND_UP(l2entries, 1024);
     return pages + l2entries + l1entries;
 }
+static size_t max_slabs_required_large(size_t bytes)
+{
+    // similar to the above, but larger page size and mapped only in a higher lvl paging structure
+    size_t pages = DIVIDE_ROUND_UP(bytes, LARGE_PAGE_SIZE);
+    size_t l1entries = DIVIDE_ROUND_UP(pages, 1024);
+    return pages + l1entries;
+}
 
 /**
  * \brief Refill slabs used for metadata
@@ -578,24 +558,31 @@ map(struct pmap     *pmap,
 {
     struct pmap_arm *pmap_arm = (struct pmap_arm *)pmap;
 
-    if(flags&FLAGS_LARGE)
-    {
-        //large page mapping
-        //size += LARGE_PAGE_OFFSET(offset);
-        //size = ROUND_UP(size, LARGE_PAGE_SIZE);
-        //offset -= LARGE_PAGE_OFFSET(offset);
-    }
-    else
-    {
+    size_t base;
+    size_t page_size;
+    size_t slabs_required;
+    
+    // adjust the mapping to be on page boundaries
+    if (flags&FLAGS_SECTION) {
+        //section mapping (1MB)
+        base = LARGE_PAGE_OFFSET(offset);
+        page_size = LARGE_PAGE_SIZE;
+        slabs_required = max_slabs_required_large(size);
+        printf("map: large path, page_size: %i, base: %i, slabs: %i, size: %i\n", page_size, base, slabs_required, size);
+    } else {
         //4k mapping
-        size   += BASE_PAGE_OFFSET(offset);
-        size    = ROUND_UP(size, BASE_PAGE_SIZE);
-        offset -= BASE_PAGE_OFFSET(offset);
+        base = BASE_PAGE_OFFSET(offset);
+        page_size = BASE_PAGE_SIZE;
+        slabs_required = max_slabs_required(size);
     }
-    
+    size   += base;
+    size    = ROUND_UP(size, page_size);
+    offset -= base;
+
     const size_t slabs_reserve = 3; // == max_slabs_required(1)
     uint64_t  slabs_free       = slab_freecount(&pmap_arm->slab);
-    size_t    slabs_required   = max_slabs_required(size) + slabs_reserve;
+
+    slabs_required += slabs_reserve;
 
     if (slabs_required > slabs_free) {
         if (get_current_pmap() == pmap) {
@@ -753,6 +740,65 @@ determine_addr(struct pmap   *pmap,
     return SYS_ERR_OK;
 }
 
+/** \brief Retrieves an address that can currently be used for large mappings
+  *
+  */
+static errval_t determine_addr_raw(struct pmap *pmap, size_t size,
+                                   size_t alignment, genvaddr_t *retvaddr)
+{
+    struct pmap_arm *pmap_arm = (struct pmap_arm *)pmap;
+
+    struct vnode *walk_pdir = pmap_arm->root.u.vnode.children;
+    assert(walk_pdir != NULL); // assume there's always at least one existing entry
+
+    if (alignment == 0) {
+        alignment = BASE_PAGE_SIZE;
+    } else {
+        alignment = ROUND_UP(alignment, BASE_PAGE_SIZE);
+    }
+    size = ROUND_UP(size, alignment);
+
+    size_t free_count = DIVIDE_ROUND_UP(size, LARGE_PAGE_SIZE);
+    //debug_printf("need %zu contiguous free pdirs\n", free_count);
+
+    // compile pdir free list
+    // barrelfish treats L1 as 1024 entries
+    bool f[1024];
+    for (int i = 0; i < 1024; i++) {
+        f[i] = true;
+    }
+    f[walk_pdir->entry] = false;
+    while (walk_pdir) {
+        assert(walk_pdir->is_vnode);
+        f[walk_pdir->entry] = false;
+        walk_pdir = walk_pdir->next;
+    }
+    genvaddr_t first_free = 384;
+    for (; first_free < 512; first_free++) {
+        if (f[first_free]) {
+            for (int i = 1; i < free_count; i++) {
+                if (!f[first_free + i]) {
+                    // advance pointer
+                    first_free = first_free+i;
+                    goto next;
+                }
+            }
+            break;
+        }
+next:
+        assert(1 == 1);// make compiler shut up about label
+    }
+    //printf("first free: %li\n", (uint32_t)first_free);
+    if (first_free + free_count <= 512) {
+        *retvaddr = first_free << 22;
+        return SYS_ERR_OK;
+    } else {
+        return LIB_ERR_OUT_OF_VIRTUAL_ADDR;
+    }
+}
+
+
+
 static errval_t do_single_modify_flags(struct pmap_arm *pmap, genvaddr_t vaddr,
                                        size_t pages, vregion_flags_t flags)
 {
@@ -886,6 +932,7 @@ deserialise(struct pmap *pmap, void *buf, size_t buflen)
 
 static struct pmap_funcs pmap_funcs = {
     .determine_addr = determine_addr,
+    .determine_addr_raw = determine_addr_raw,
     .map = map,
     .unmap = unmap,
     .modify_flags = modify_flags,
index 78fbd7d..08d62df 100644 (file)
@@ -35,9 +35,8 @@
 #define META_DATA_RESERVED_BASE ((lvaddr_t)1UL*1024*1024*1024)
 #define META_DATA_RESERVED_SIZE (X86_32_BASE_PAGE_SIZE * 1200)
 
-//TODO better name/condition
+// flags for large pages
 #define FLAGS_LARGE 0x0100
-#define FLAGS_UNMAP 0x01
 
 /**
  * \brief Translate generic vregion flags to architecture specific pmap flags
@@ -292,6 +291,19 @@ static struct vnode *find_ptable(struct pmap_x86 *pmap, genvaddr_t base)
     return find_vnode(pdir, X86_32_PDIR_BASE(base));
 }
 
+static struct vnode *find_pdir(struct pmap_x86 *pmap, genvaddr_t base)
+{
+    struct vnode *root = &pmap->root;
+    assert(root != NULL);
+
+#ifdef CONFIG_PAE
+    // PDPT mapping
+    return find_vnode(root, X86_32_PDPT_BASE(base));
+#else
+    return root;
+#endif
+}
+
 static errval_t do_single_map(struct pmap_x86 *pmap, genvaddr_t vaddr, genvaddr_t vend,
                               struct capref frame, size_t offset, size_t pte_count,
                               vregion_flags_t flags)
@@ -305,7 +317,6 @@ static errval_t do_single_map(struct pmap_x86 *pmap, genvaddr_t vaddr, genvaddr_
     errval_t err;
     size_t base;
     if (flags&FLAGS_LARGE) {
-        printf("pmap_single_map: large\n");
         //4M/2M(PAE) mapping
         err = get_pdir(pmap, vaddr, &ptable);
         base = X86_32_PDIR_BASE(vaddr);
@@ -357,13 +368,11 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
     size_t page_size;
     size_t base;
 
+    // mapping specific parts
     if(flags&FLAGS_LARGE) {
-        printf("pmap_do_map: large\n");
         //4M/2M (PAE) pages
         page_size = X86_32_LARGE_PAGE_SIZE;
         base = X86_32_PDIR_BASE(vaddr);
-        //printf("pmap_do_map: large: pte: %i\n", DIVIDE_ROUND_UP(size, page_size));
-        //printf("pmap_do_map: large: same_pdpt: %i\n", is_same_pdpt(vaddr, vaddr+size));
     } else {
         //4k mapping
         page_size = X86_32_BASE_PAGE_SIZE;
@@ -376,7 +385,6 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
 
     if (is_same_pdir(vaddr, vend) || (is_same_pdpt(vaddr, vend) && flags&FLAGS_LARGE)) {
         // fast path
-        //printf("pmap_do_map: fast path, pte_count: %i, %i\n", pte_count, DIVIDE_ROUND_UP(size, page_size));
         err = do_single_map(pmap, vaddr, vend, frame, offset, pte_count, flags);
         if (err_is_fail(err)) {
             return err_push(err, LIB_ERR_PMAP_DO_MAP);
@@ -455,7 +463,7 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
     return SYS_ERR_OK;
 }
 
-/// Computer upper limit on number of slabs required to perform a mapping
+/// Compute upper limit on number of slabs required to perform a mapping
 static size_t max_slabs_for_mapping(size_t bytes)
 {
     size_t max_pages  = DIVIDE_ROUND_UP(bytes, X86_32_BASE_PAGE_SIZE);
@@ -574,7 +582,6 @@ static errval_t map(struct pmap *pmap, genvaddr_t vaddr, struct capref frame,
     // Adjust the parameters to page boundaries
     if(flags&FLAGS_LARGE) {
         // 4M pages/2M pages(PAE)
-        printf("map: large path\n");
         size   += X86_32_LARGE_PAGE_OFFSET(offset);
         size    = ROUND_UP(size, X86_32_LARGE_PAGE_SIZE);
         offset -= X86_32_LARGE_PAGE_OFFSET(offset);
@@ -610,19 +617,36 @@ static errval_t map(struct pmap *pmap, genvaddr_t vaddr, struct capref frame,
 
     //printf("[map call do_map] vaddr = 0x%"PRIxGENVADDR", flag = %x\n", vaddr, (int)flags);
     err = do_map(x86, vaddr, frame, offset, size, flags, retoff, retsize);
-    if(flags&FLAGS_LARGE)
-    {
-        printf("map: large map complete\n");
-    }
     return err;
 }
 
 static errval_t do_single_unmap(struct pmap_x86 *pmap, genvaddr_t vaddr, size_t pte_count, bool delete_cap)
 {
     errval_t err;
-    struct vnode *pt = find_ptable(pmap, vaddr);
+    bool large_flag = false;
+    struct vnode *page;
+    //determine if we unmap a large page
+    if ((page = find_pdir(pmap, vaddr)) != NULL) {
+#ifdef CONFIG_PAE        
+        if ((page = find_vnode(page, X86_32_PDPT_BASE(vaddr))) != NULL) {
+#else
+        if ((page = find_vnode(page, X86_32_PDIR_BASE(vaddr))) != NULL) {
+#endif
+            large_flag = page->u.frame.flags&FLAGS_LARGE;
+        }
+    }
+    
+    struct vnode *pt;
+    size_t base;
+    if (large_flag) {
+        pt = find_pdir(pmap, vaddr);
+        base = X86_32_PDIR_BASE(vaddr);
+    } else {
+        pt = find_ptable(pmap, vaddr);
+        base = X86_32_PTABLE_BASE(vaddr);
+    }
     if (pt) {
-        struct vnode *page = find_vnode(pt, X86_32_PTABLE_BASE(vaddr));
+        page = find_vnode(pt, base);
         if (page && page->u.frame.pte_count == pte_count) {
             err = vnode_unmap(pt->u.vnode.cap, page->u.frame.cap, page->entry, page->u.frame.pte_count);
             if (err_is_fail(err)) {
@@ -641,6 +665,7 @@ static errval_t do_single_unmap(struct pmap_x86 *pmap, genvaddr_t vaddr, size_t
             slab_free(&pmap->slab, page);
         }
         else {
+            printf("couldn't find vnode\n");
             return LIB_ERR_PMAP_FIND_VNODE;
         }
     }
@@ -662,12 +687,32 @@ static errval_t unmap(struct pmap *pmap, genvaddr_t vaddr, size_t size,
     //printf("[unmap] 0x%"PRIxGENVADDR", %zu\n", vaddr, size);
     errval_t err, ret = SYS_ERR_OK;
     struct pmap_x86 *x86 = (struct pmap_x86*)pmap;
-    size = ROUND_UP(size, X86_32_BASE_PAGE_SIZE);
+    
+    //determine if we unmap a larger page
+    struct vnode* page = NULL;
+    bool large_flag = false;
+    //find table, then entry
+    if ((page = find_pdir(x86, vaddr)) != NULL) {
+#ifdef CONFIG_PAE        
+        if ((page = find_vnode(page, X86_32_PDPT_BASE(vaddr))) != NULL) {
+#else
+        if ((page = find_vnode(page, X86_32_PDIR_BASE(vaddr))) != NULL) {
+#endif
+            large_flag = page->u.frame.flags&FLAGS_LARGE;
+        }
+    }
+    size_t page_size = X86_32_BASE_PAGE_SIZE;
+    if (large_flag) {
+        //large 2M page
+        page_size = X86_32_LARGE_PAGE_SIZE;
+    }
+    
+    size = ROUND_UP(size, page_size);
     genvaddr_t vend = vaddr + size;
 
-    if (is_same_pdir(vaddr, vend)) {
+    if (is_same_pdir(vaddr, vend) || (is_same_pdpt(vaddr, vend) && large_flag)) {
         // fast path
-        err = do_single_unmap(x86, vaddr, size / X86_32_BASE_PAGE_SIZE, false);
+        err = do_single_unmap(x86, vaddr, size / page_size, false);
         if (err_is_fail(err)) {
             return err_push(err, LIB_ERR_PMAP_UNMAP);
         }
@@ -681,14 +726,14 @@ static errval_t unmap(struct pmap *pmap, genvaddr_t vaddr, size_t size,
         }
 
         // unmap full leaves
-        vaddr += c * X86_32_BASE_PAGE_SIZE;
+        vaddr += c * page_size;
         while (get_addr_prefix(vaddr) < get_addr_prefix(vend)) {
             c = X86_32_PTABLE_SIZE;
             err = do_single_unmap(x86, vaddr, X86_32_PTABLE_SIZE, true);
             if (err_is_fail(err)) {
                 return err_push(err, LIB_ERR_PMAP_UNMAP);
             }
-            vaddr += c * X86_32_BASE_PAGE_SIZE;
+            vaddr += c * page_size;
         }
 
         // unmap remaining part
@@ -877,6 +922,9 @@ static errval_t dump(struct pmap *pmap, struct pmap_dump_info *buf, size_t bufle
     return SYS_ERR_OK;
 }
 
+/** \brief Retrieves an address that can currently be used for large mappings
+  *
+  */
 static errval_t determine_addr_raw(struct pmap *pmap, size_t size,
                                    size_t alignment, genvaddr_t *retvaddr)
 {
@@ -893,7 +941,7 @@ static errval_t determine_addr_raw(struct pmap *pmap, size_t size,
     size = ROUND_UP(size, alignment);
 
     size_t free_count = DIVIDE_ROUND_UP(size, LARGE_PAGE_SIZE);
-    debug_printf("need %zu contiguous free pdirs\n", free_count);
+    //debug_printf("need %zu contiguous free pdirs\n", free_count);
 
     // compile pdir free list
     bool f[1024];
@@ -922,7 +970,7 @@ static errval_t determine_addr_raw(struct pmap *pmap, size_t size,
 next:
         assert(1 == 1);// make compiler shut up about label
     }
-    printf("first free: %li\n", (uint32_t)first_free);
+    //printf("first free: %li\n", (uint32_t)first_free);
     if (first_free + free_count <= 512) {
         *retvaddr = first_free << 22;
         return SYS_ERR_OK;
index 070d85d..3468543 100644 (file)
@@ -37,9 +37,9 @@
 #define META_DATA_RESERVED_BASE (PML4_MAPPING_SIZE * (disp_get_core_id() + 1))
 #define META_DATA_RESERVED_SIZE (X86_64_BASE_PAGE_SIZE * 20000)
 
-//debug page_flag
+// large mapping flags
 #define FLAGS_LARGE 0x0100
-#define FLAGS_HUGE  0x1000
+#define FLAGS_HUGE  0x0200
 
 /**
  * \brief Translate generic vregion flags to architecture specific pmap flags
@@ -76,6 +76,10 @@ static inline genvaddr_t get_addr_prefix(genvaddr_t va)
 {
     return va >> X86_64_LARGE_PAGE_BITS;
 }
+static inline genvaddr_t get_addr_prefix_large(genvaddr_t va)
+{
+    return va >> X86_64_HUGE_PAGE_BITS;
+}
 static bool has_vnode(struct vnode *root, uint32_t entry, size_t len)
 {
     assert(root != NULL);
@@ -367,12 +371,12 @@ static errval_t do_single_map(struct pmap_x86 *pmap, genvaddr_t vaddr, genvaddr_
     struct vnode *ptable;
     errval_t err;
     size_t table_base;
-    //TODO meaningful condition
+    
+    // get the right paging table and address part
     if(flags&FLAGS_LARGE) {
         //large 2M pages, mapped into pdir
         err = get_pdir(pmap, vaddr, &ptable);
         table_base = X86_64_PDIR_BASE(vaddr);
-        printf("do_single_map: large, flags: %x\n", (unsigned int) flags);
     } else if (flags&FLAGS_HUGE) {
         //huge 1GB pages, mapped into pdpt
         err = get_pdpt(pmap, vaddr, &ptable);
@@ -405,12 +409,7 @@ static errval_t do_single_map(struct pmap_x86 *pmap, genvaddr_t vaddr, genvaddr_
     page->u.frame.flags = flags;
     page->u.frame.pte_count = pte_count;
 
-    // do map
-    if (flags&FLAGS_LARGE)
-    {
-        printf("cap: --, frame: --, table_base: %lx, pmap_flags: %lx, offset: %lx, pte_count: %lx\n", (unsigned long) table_base, (unsigned long)pmap_flags, (unsigned long) offset, (unsigned long) pte_count);
-    }
-    
+    // do map    
     err = vnode_map(ptable->u.vnode.cap, frame, table_base,
                     pmap_flags, offset, pte_count);
     if (err_is_fail(err)) {
@@ -429,16 +428,13 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
 {
     errval_t err;
 
-
-    // determine page size
+    // determine page size and relevant address part
     size_t page_size;
     size_t table_base;
-    // table_size same in x86_64
     if (flags&FLAGS_LARGE) {
         // large page branch (2MB)
         page_size = X86_64_LARGE_PAGE_SIZE;
         table_base = X86_64_PDIR_BASE(vaddr);
-        printf("do_map: large\n");
     } else if (flags&FLAGS_HUGE) {
         // huge page branch (1GB)
         page_size = X86_64_HUGE_PAGE_SIZE;
@@ -448,10 +444,11 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
         page_size = X86_64_BASE_PAGE_SIZE;
         table_base = X86_64_PTABLE_BASE(vaddr);
     }
+    
+    // round to the next full page
     size = ROUND_UP(size, page_size);
     size_t pte_count = DIVIDE_ROUND_UP(size, page_size);
     genvaddr_t vend = vaddr + size;
-    //printf("\tpage_size: %i, size: %i, pte count: %i\n", (int)page_size, (int)size, (int)pte_count);
 
 #if 0
     struct frame_identity fi;
@@ -486,8 +483,20 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
             return err_push(err, LIB_ERR_PMAP_DO_MAP);
         }
 
+        // XXX: huge pages not yet supportet on the long path
+        //      but determine_addr_raw gives us empty pdpt entries,
+        //      so should do it one address at a time anyways
+        
+        // this if/else could be pushed up to the other page specific switch
+        // for performance reasons, kept here so far for readability
+        bool addr_prefix;
+        if (flags&FLAGS_LARGE) {
+            addr_prefix = (get_addr_prefix_large(temp_end) < get_addr_prefix_large(vend));
+        } else {
+            addr_prefix = (get_addr_prefix(temp_end) < get_addr_prefix(vend));
+        }
         // map full leaves
-        while (get_addr_prefix(temp_end) < get_addr_prefix(vend)) {
+        while (addr_prefix) {
             // update vars
             vaddr = temp_end;
             temp_end = vaddr + X86_64_PTABLE_SIZE * page_size;
@@ -511,6 +520,13 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
             if (err_is_fail(err)) {
                 return err_push(err, LIB_ERR_PMAP_DO_MAP);
             }
+            
+            // update loop condition
+            if (flags&FLAGS_LARGE) {
+                addr_prefix = (get_addr_prefix_large(temp_end) < get_addr_prefix_large(vend));
+            } else {
+                addr_prefix = (get_addr_prefix(temp_end) < get_addr_prefix(vend));
+            }
         }
 
         // map remaining part
@@ -676,7 +692,6 @@ static errval_t map(struct pmap *pmap, genvaddr_t vaddr, struct capref frame,
         size    = ROUND_UP(size, LARGE_PAGE_SIZE);
         offset -= LARGE_PAGE_OFFSET(offset);
         max_slabs = max_slabs_for_mapping_large(size);
-        printf("map: large\n");
     } else if (flags&FLAGS_HUGE) {
         // case huge pages (1GB)
         size   += HUGE_PAGE_OFFSET(offset);
@@ -814,12 +829,15 @@ static errval_t unmap(struct pmap *pmap, genvaddr_t vaddr, size_t size,
         }
     }
     size_t page_size = X86_64_BASE_PAGE_SIZE;
+    size_t table_base = X86_64_PTABLE_BASE(vaddr);
     if (large_flag) {
         //large 2M page
         page_size = X86_64_LARGE_PAGE_SIZE;
+        table_base = X86_64_PDIR_BASE(vaddr);
     } else if (huge_flag) {
         //huge 1GB page
         page_size = X86_64_HUGE_PAGE_SIZE;
+        table_base = X86_64_PDPT_BASE(vaddr);
     }
         
     size = ROUND_UP(size, page_size);
@@ -836,11 +854,8 @@ static errval_t unmap(struct pmap *pmap, genvaddr_t vaddr, size_t size,
     }
     else { // slow path
         // unmap first leaf
-        uint32_t c = X86_64_PTABLE_SIZE - X86_64_PTABLE_BASE(vaddr);
-        
-        if(large_flag) {
-            c = X86_64_PTABLE_SIZE - X86_64_PDIR_BASE(vaddr);
-        }
+        uint32_t c = X86_64_PTABLE_SIZE - table_base;
+    
         err = do_single_unmap(x86, vaddr, c, false);
         if (err_is_fail(err)) {
             printf("error first leaf\n");
@@ -849,7 +864,15 @@ static errval_t unmap(struct pmap *pmap, genvaddr_t vaddr, size_t size,
 
         // unmap full leaves
         vaddr += c * page_size;
-        while (get_addr_prefix(vaddr) < get_addr_prefix(vend)) {
+        bool addr_prefix;
+        // this if/else could be combined with the one above for performance reasons,
+        // kept here for readability
+        if (large_flag) {
+            addr_prefix = (get_addr_prefix_large(vaddr) < get_addr_prefix_large(vend));
+        } else {
+            addr_prefix = (get_addr_prefix(vaddr) < get_addr_prefix(vend));
+        }
+        while (addr_prefix) {
             c = X86_64_PTABLE_SIZE;
             err = do_single_unmap(x86, vaddr, X86_64_PTABLE_SIZE, true);
             if (err_is_fail(err)) {
@@ -857,6 +880,13 @@ static errval_t unmap(struct pmap *pmap, genvaddr_t vaddr, size_t size,
                 return err_push(err, LIB_ERR_PMAP_UNMAP);
             }
             vaddr += c * page_size;
+            
+            // update condition
+            if (large_flag) {
+                addr_prefix = (get_addr_prefix_large(vaddr) < get_addr_prefix_large(vend));
+            } else {
+                addr_prefix = (get_addr_prefix(vaddr) < get_addr_prefix(vend));
+            }
         }
 
         // unmap remaining part
@@ -864,6 +894,8 @@ static errval_t unmap(struct pmap *pmap, genvaddr_t vaddr, size_t size,
 
         if (large_flag) {
             c = X86_64_PDIR_BASE(vend) - X86_64_PDIR_BASE(vaddr);
+        } else if (huge_flag) {
+            c = X86_64_PDPT_BASE(vend) - X86_64_PDPT_BASE(vaddr);
         }
         if (c) {
             err = do_single_unmap(x86, vaddr, c, true);
@@ -1102,27 +1134,25 @@ static errval_t determine_addr_raw(struct pmap *pmap, size_t size,
     for (int i = 0; i < 512; i++) {
         f[i] = true;
     }
-    debug_printf("entry: %d\n", walk_pml4->entry);
+    //debug_printf("entry: %d\n", walk_pml4->entry);
     f[walk_pml4->entry] = false;
     while (walk_pml4) {
-        debug_printf("looping over pml4 entries\n");
+        //debug_printf("looping over pml4 entries\n");
         assert(walk_pml4->is_vnode);
         f[walk_pml4->entry] = false;
         walk_pml4 = walk_pml4->next;
     }
     genvaddr_t first_free = 16;
     for (; first_free < 512; first_free++) {
-        debug_printf("f[%"PRIuGENVADDR"] = %d\n", first_free, f[first_free]);
+        //debug_printf("f[%"PRIuGENVADDR"] = %d\n", first_free, f[first_free]);
         if (f[first_free]) {
             break;
         }
     }
-    debug_printf("first_free: %"PRIuGENVADDR"\n", first_free);
+    //debug_printf("first_free: %"PRIuGENVADDR"\n", first_free);
     if (first_free < 512) {
-        debug_printf("first_free: %"PRIuGENVADDR"\n", first_free);
-        debug_printf("first_free shifted: %"PRIuGENVADDR"\n", first_free<<39);
+        //debug_printf("first_free: %"PRIuGENVADDR"\n", first_free);
         *retvaddr = first_free << 39;
-        printf("addr: %lx\n", *retvaddr);
         return SYS_ERR_OK;
     } else {
         return LIB_ERR_OUT_OF_VIRTUAL_ADDR;
diff --git a/usr/bench/largepage/Hakefile b/usr/bench/largepage/Hakefile
new file mode 100644 (file)
index 0000000..aa45141
--- /dev/null
@@ -0,0 +1,18 @@
+--------------------------------------------------------------------------
+-- Copyright (c) 2007-2010, ETH Zurich.
+-- 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.
+--
+-- Hakefile for bmp_bench
+-- 
+--------------------------------------------------------------------------
+
+[
+build application { target = "largepage_64_bench",
+                  cFiles = [ "largepage_64_bench.c" ],
+                  addLibraries = [ "bench"]
+                  }
+]
diff --git a/usr/bench/largepage/largepage_64_bench.c b/usr/bench/largepage/largepage_64_bench.c
new file mode 100644 (file)
index 0000000..1527321
--- /dev/null
@@ -0,0 +1,312 @@
+/**
+ * \file
+ * \brief Test program for large page code
+ */
+
+/*
+ * Copyright (c) 2013, ETH Zurich.
+ * 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.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <barrelfish/nameservice_client.h>
+#include <barrelfish/sys_debug.h>
+#include <bench/bench.h>
+
+#define SAFE_VADDR (genvaddr_t)(8ULL<<39)
+#define SAFE_PMAP_ADDR (genvaddr_t)(9ULL<<39)
+//0b 0000 0000 0000 0000 0000 0100 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+#define SAFE_PMAP_ADDR_L ((genvaddr_t) (12ULL<<39))
+// 40M
+#define DEFAULT_SIZE 30*X86_64_LARGE_PAGE_SIZE
+
+#define LARGE_PAGE_SIZE X86_64_LARGE_PAGE_SIZE
+
+#define RUN_COUNT 50
+
+unsigned long mean4k;
+unsigned long mean2m;
+unsigned long min4k;
+unsigned long min2m;
+unsigned long mean4krand;
+unsigned long mean2mrand;
+unsigned long min4krand;
+unsigned long min2mrand;
+unsigned long max4krand;
+unsigned long max2mrand;
+unsigned long max4k;
+unsigned long max2m;
+
+unsigned long mean4kshort;
+unsigned long mean2mshort;
+unsigned long mean4kshortrand;
+unsigned long mean2mshortrand;
+unsigned long min4kshort;
+unsigned long min2mshort;
+unsigned long min4kshortrand;
+unsigned long min2mshortrand;
+unsigned long max4kshort;
+unsigned long max2mshort;
+unsigned long max4kshortrand;
+unsigned long max2mshortrand;
+/*static paging_x86_64_flags_t PAGE_DEFAULT_ACCESS =
+    PTABLE_USER_SUPERVISOR |
+    PTABLE_EXECUTE_DISABLE |
+    PTABLE_READ_WRITE;
+ */   
+static vregion_flags_t PMAP_DEFAULT_ACCESS =
+    VREGION_FLAGS_READ_WRITE;
+
+static void test_region(uint32_t *buf, size_t size, bool large, bool area)
+{
+    cycles_t runs[RUN_COUNT];
+    cycles_t start, end;
+    uint64_t mean = 0;
+    unsigned long min = 0;
+    unsigned long max = 0;
+    printf("base address: %lx\n", (uint64_t) buf);
+    
+    //sequential access
+    for (int j = 0; j < RUN_COUNT; j++) {
+        
+        start = bench_tsc()/1000;
+        for (unsigned long i = 0; i < size; i+=4) {
+            
+            buf[i/4] = i;
+        }
+        for (unsigned long i = 0; i < size; i+=4) {
+            assert(buf[i/4] == i);
+        }
+        end = bench_tsc()/1000;
+        runs[j] = end-start;
+        mean += (unsigned int) runs[j];
+        if (runs[j] < min || j == 0) {min = runs[j];}
+        if (runs[j] > max) {max = runs[j];}
+        printf("run: %u, cycles: %u\n", j, (unsigned int) runs[j]);
+    }
+    mean = mean/RUN_COUNT;
+    printf("\naverage cycles to write the whole area: %u\n", (unsigned int) mean);
+    if(!large && !area) {
+        mean4k = mean;
+        min4k = min;
+        max4k = max;
+    }
+    else if (large && !area) {
+        mean2m = mean;
+        min2m = min;
+        max2m = max;
+    }
+    else if (!large && area) {
+        mean4kshort = mean;
+        min4kshort = min;
+        max4kshort = max;
+    } else {
+        mean2mshort = mean;
+        min2mshort = min;
+        max2mshort = max;
+    }
+    
+    //random access
+    //generate 1M random number array
+    unsigned int* addrs;
+    min = 0;
+    max = 0;
+    mean = 0;
+    addrs = malloc(2000000*sizeof(unsigned int));
+    printf("malloc'd\n");
+    for (int i = 0; i<2000000; i++)
+    {  
+        addrs[i] = (rand() % (size/4));
+    }
+    printf("randomised\n");
+    for (int j = 0; j < RUN_COUNT; j++) {
+        
+        start = bench_tsc()/1000;
+        for (int i = 0; i < 2000000; i++) {
+            buf[addrs[i]] = addrs[i];
+        }
+        for (unsigned long i = 0; i < 2000000; i++) {
+            assert(buf[addrs[i]] == addrs[i]);
+        }
+        end = bench_tsc()/1000;
+        runs[j] = end-start;
+        mean += (unsigned int) runs[j];
+        if (runs[j] < min || j == 0) {min = runs[j];}
+        if (runs[j] > max) {max = runs[j];}
+        printf("run: %u, cycles: %u\n", j, (unsigned int) runs[j]);
+    }
+    mean = mean/RUN_COUNT;
+    printf("\naverage cycles to write the whole area randomly: %u\n", (unsigned int) mean);
+    if(!large && !area) {
+        mean4krand = mean;
+        min4krand = min;
+        max4krand = max;
+    }
+    else if (large && !area){
+        mean2mrand = mean;
+        min2mrand = min;
+        max2mrand = max;
+    }else if (!large && area) {
+        mean4kshortrand = mean;
+        min4kshortrand = min;
+        max4kshortrand = max;
+    } else {
+        mean2mshortrand = mean;
+        min2mshortrand = min;
+        max2mshortrand = max;
+    }
+
+}
+
+int main(void)
+{
+    struct capref frame;
+    size_t bytes = DEFAULT_SIZE;
+    errval_t err;
+    mean4k = 0;
+    mean2m = 0;
+    genvaddr_t address;
+
+    
+    //normal pages via pmap interface
+    printf("\nstart 4k map with pmap\n");
+    err = frame_alloc(&frame, bytes, &bytes);
+    if (err_is_fail(err))
+    {  
+        printf("error in frame_alloc: %s\n", err_getstring(err));
+        exit(1);
+    }
+    assert(bytes >= DEFAULT_SIZE);
+    printf("    get pmap\n");
+    struct pmap *pmap = get_current_pmap();
+    
+    printf("    obtain address\n");
+    err = pmap->f.determine_addr_raw(pmap, bytes, X86_64_BASE_PAGE_SIZE, &address);
+    if (err_is_fail(err))
+    {
+        printf("error in determine_addr_raw: %s\n", err_getstring(err));
+        exit(1);
+    }
+    
+    printf("    map\n");
+    err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS, NULL, &bytes);
+    if (err_is_fail(err))
+    {
+        printf("error in pmap: %s\n", err_getstring(err));
+        exit(1);
+    }
+    printf("addr: %lx\n", address);
+    test_region((uint32_t*)address, DEFAULT_SIZE, false, false);
+    
+    printf("\tunmap\n");
+    err = pmap->f.unmap(pmap, address, bytes, NULL);
+    if (err_is_fail(err))
+    {
+        printf("error in unmap: %s\n", err_getstring(err));
+        exit(1);
+    }
+   
+    //large page via pmap interface
+    printf("start 2m map with pmap\n");
+    bytes = DEFAULT_SIZE;
+    struct capref frame2;
+    err = frame_alloc(&frame2, bytes, &bytes);
+    if (err_is_fail(err))
+    {  
+        printf("error in frame_alloc: %s\n", err_getstring(err));
+        exit(1);
+    }
+    assert(bytes >= DEFAULT_SIZE);
+    pmap = get_current_pmap();
+
+    printf("determine address\n");
+    err = pmap->f.determine_addr_raw(pmap, bytes, X86_64_LARGE_PAGE_SIZE, &address);
+    if (err_is_fail(err))
+    {
+        printf("error in determine_addr_raw: %s\n", err_getstring(err));
+        exit(1);
+    }
+    
+    printf("map\n");
+    err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+    if (err_is_fail(err))
+    {
+        printf("error in pmap: %s\n", err_getstring(err));
+        exit(1);
+    }
+    printf("addr: %lx\n", address);
+    test_region((uint32_t*)address, DEFAULT_SIZE, true, false);
+    
+    err = pmap->f.unmap(pmap, address, bytes, NULL);
+    if (err_is_fail(err))
+    {
+        printf("error in unmap: %s\n", err_getstring(err));
+        exit(1);
+    }
+    //small area 4k
+    bytes = LARGE_PAGE_SIZE;
+    err = frame_alloc(&frame, bytes, &bytes);
+    if (err_is_fail(err))
+    {  
+        printf("error in frame_alloc: %s\n", err_getstring(err));
+        exit(1);
+    }
+    assert(bytes >= LARGE_PAGE_SIZE);
+    pmap = get_current_pmap();
+    err = pmap->f.map(pmap, SAFE_PMAP_ADDR, frame, 0, bytes, PMAP_DEFAULT_ACCESS, NULL, &bytes);
+    if (err_is_fail(err))
+    { 
+        printf("error in pmap small 4k\n");
+        exit(1);
+    }
+    test_region((uint32_t*) SAFE_PMAP_ADDR, LARGE_PAGE_SIZE, false, true); 
+    
+    //small area 2m
+    bytes = LARGE_PAGE_SIZE;
+    err = frame_alloc(&frame, bytes, &bytes);
+    if (err_is_fail(err))
+    {  
+        printf("error in frame_alloc: %s\n", err_getstring(err));
+        exit(1);
+    }
+    assert(bytes >= LARGE_PAGE_SIZE);
+    pmap = get_current_pmap();
+
+    printf("map\n");
+    err = pmap->f.map(pmap, SAFE_PMAP_ADDR_L, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+    if (err_is_fail(err))
+    {
+        printf("error in pmap: %s\n", err_getstring(err));
+        exit(1);
+    }
+    printf("addr: %lx\n", SAFE_PMAP_ADDR_L);
+    test_region((uint32_t*)SAFE_PMAP_ADDR_L, LARGE_PAGE_SIZE, true, true);
+    
+    
+        
+    printf("large area\n");
+    printf("average 4k: %lu, average 2m: %lu\n", mean4k, mean2m);
+    printf("minimal 4k: %lu, minimal 2m: %lu\n", min4k, min2m);
+    printf("maximal 4k: %lu, maximal 2m: %lu\n", max4k, max2m);
+    printf("random: average 4k: %lu, average 2m: %lu\n", mean4krand, mean2mrand);
+    printf("random:minimal 4k: %lu, minimal 2m: %lu\n", min4krand, min2mrand);
+    printf("random:maximal 4k: %lu, maximal 2m: %lu\n\n", max4krand, max2mrand);
+    printf("short area\n");
+    printf("average 4k: %lu, average 2m: %lu\n", mean4kshort, mean2mshort);
+    printf("minimal 4k: %lu, minimal 2m: %lu\n", min4kshort, min2mshort);
+    printf("maximal 4k: %lu, maximal 2m: %lu\n", max4kshort, max2mshort);
+    printf("random: average 4k: %lu, average 2m: %lu\n", mean4kshortrand, mean2mshortrand);
+    printf("random:minimal 4k: %lu, minimal 2m: %lu\n", min4kshortrand, min2mshortrand);
+    printf("random:maximal 4k: %lu, maximal 2m: %lu\n", max4kshortrand, max2mshortrand);
+    printf("exited successfully\n");
+    return 0;
+}
diff --git a/usr/vnode_map_32/Hakefile b/usr/vnode_map_32/Hakefile
new file mode 100644 (file)
index 0000000..fc7e5c6
--- /dev/null
@@ -0,0 +1,17 @@
+--------------------------------------------------------------------------
+-- Copyright (c) 2013, ETH Zurich.
+-- 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, Universitaetsstr. 6, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for /usr/vnode_map_test
+-- 
+--------------------------------------------------------------------------
+
+[ build application { target = "vnode_map_32",
+                      cFiles = [ "vnode_map_32.c" ]
+                    }
+]
+
diff --git a/usr/vnode_map_32/vnode_map_32.c b/usr/vnode_map_32/vnode_map_32.c
new file mode 100644 (file)
index 0000000..345024a
--- /dev/null
@@ -0,0 +1,190 @@
+/**
+ * \file
+ * \brief Test program for large page code
+ * 
+ * For this to work, Barrelfish needs to be compiled with the
+ * PSE == true configuration enabled in hake/config.hs
+ */
+
+/*
+ * Copyright (c) 2013, ETH Zurich.
+ * 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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <stdio.h>
+#include <limits.h>
+
+#define SAFE_VADDR (genvaddr_t)0x320000//(8ULL<<18)
+#define SAFE_PMAP_ADDR (genvaddr_t)(9ULL<<39)
+
+//4M/2M (in PAE)
+#define DEFAULT_SIZE X86_32_LARGE_PAGE_SIZE
+
+    
+static vregion_flags_t PMAP_DEFAULT_ACCESS =
+    VREGION_FLAGS_READ_WRITE;
+
+static void test_region(uint32_t *buf, size_t size)
+{
+    int j = 0;
+    for (int i = 0; i < size; i+=4) {
+        j+=4;
+        if( (size-j) < 200)
+        {
+        printf("%i, ", i);
+        }
+        
+        buf[i/4] = i;
+    }
+    for (int i = 0; i < size; i+=4) {
+        assert(buf[i/4] == i);
+    }
+
+    printf("\n\n");
+}
+
+
+int main(void)
+{
+    struct capref frame, smallframe;
+    size_t bytes = DEFAULT_SIZE;
+    size_t bits = 4*1024;
+    uint32_t address;
+    struct memobj a;
+    errval_t err;
+    printf("\tpagesize: %i, \taddr: %i\n", (int)bytes, (int)SAFE_VADDR);
+
+    //get 4k frame cap
+    err = frame_alloc(&smallframe, bits, &bits);
+    assert(err_is_ok(err));
+    assert(bits >= 4*1024);
+    // get 2M/4M frame cap
+    err = frame_alloc(&frame, bytes, &bytes);
+    assert(err_is_ok(err));
+    assert(bytes >= DEFAULT_SIZE);
+
+//test determine_addr as address obtainer
+#if 1
+    printf("determine_addr 4k\n");
+    
+    //determine address
+    a.size = bits;
+    address = 0;
+    struct pmap *pmap = get_current_pmap();
+    err = pmap->f.determine_addr_raw(pmap, a.size, BASE_PAGE_SIZE, (genvaddr_t*)&address);
+    printf("address: %x\n", (unsigned int) address);
+    if (err_is_fail(err))
+    {
+        printf("error in determine_addr: %s\n", err_getstring(err));
+        exit(1);
+    }
+    
+    err = pmap->f.map(pmap, address, smallframe, 0, bits, PMAP_DEFAULT_ACCESS, NULL, &bits);
+    if (err_is_fail(err))
+    {
+        printf("error in pmap: %s\n", err_getstring(err));
+        exit(1);
+    }
+    test_region((uint32_t*)address, bits);
+    
+    err = pmap->f.unmap(pmap, address, bits, NULL);
+    if (err_is_fail(err))
+    {
+        printf("error in unmap: %s\n", err_getstring(err));
+        exit(1);
+    } 
+#endif
+
+    
+// test determine_addr_raw for large pages
+// also test unmap on fast path
+#if 1
+    printf("determine_addr 2m\n");
+    bytes = DEFAULT_SIZE;
+    err = frame_alloc(&frame, bytes, &bytes);
+    assert(err_is_ok(err));
+    assert(bytes >= DEFAULT_SIZE);
+    
+    a.size = bytes;
+    printf("a.size: %x, %i\n", (unsigned int) a.size, (unsigned int) a.size);
+    address = 0;
+    pmap = get_current_pmap();
+    err = pmap->f.determine_addr_raw(pmap, a.size, LARGE_PAGE_SIZE, (genvaddr_t*)&address);
+    printf("address: %lx\n", (uint32_t) address);
+    if(err_is_fail(err))
+    {
+        printf("error in determine_addr: %s\n", err_getstring(err));
+        exit(1);
+    }
+
+//for loop to test unmap
+for(int i=0; i<10; ++i) {
+printf("map %i\n", i);    
+    err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+    if (err_is_fail(err))
+    {
+        printf("error in pmap: %s\n", err_getstring(err));
+        exit(1);
+    }
+    printf("address: %lx\n", (uint32_t) address);
+    test_region((uint32_t*)address, DEFAULT_SIZE);
+    
+    err = pmap->f.unmap(pmap, address, bytes, NULL);
+    if (err_is_fail(err))
+    {
+        printf("error in unmap: %s\n", err_getstring(err));
+        exit(1);
+    } 
+}//endfor
+#endif
+
+
+// test determine_addr_raw for multiple large pages
+// also test unmap on slow path
+#if 1
+    printf("determine_addr 2m multiple\n");
+    bytes = 30*DEFAULT_SIZE;
+    err = frame_alloc(&frame, bytes, &bytes);
+    assert(err_is_ok(err));
+    assert(bytes >= 30*DEFAULT_SIZE);
+    
+    a.size = bytes;
+    printf("a.size: %x, %i\n", (unsigned int) a.size, (unsigned int) a.size);
+    address = 0;
+    pmap = get_current_pmap();
+    err = pmap->f.determine_addr_raw(pmap, a.size, LARGE_PAGE_SIZE, (genvaddr_t*)&address);
+    printf("address: %lx\n", (uint32_t) address);
+    if(err_is_fail(err))
+    {
+        printf("error in determine_addr: %s\n", err_getstring(err));
+        exit(1);
+    }
+
+//for loop to test unmap
+for(int i=0; i<10; ++i) {
+printf("map %i\n", i);    
+    err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+    if (err_is_fail(err))
+    {
+        printf("error in pmap: %s\n", err_getstring(err));
+        exit(1);
+    }
+    printf("address: %lx\n", (uint32_t) address);
+    test_region((uint32_t*)address, bytes);
+    
+    err = pmap->f.unmap(pmap, address, bytes, NULL);
+    if (err_is_fail(err))
+    {
+        printf("error in unmap: %s\n", err_getstring(err));
+        exit(1);
+    } 
+}//endfor
+#endif
+    printf("exited successfully\n");
+    return 0;
+}
diff --git a/usr/vnode_map_test/Hakefile b/usr/vnode_map_test/Hakefile
new file mode 100644 (file)
index 0000000..310ac09
--- /dev/null
@@ -0,0 +1,17 @@
+--------------------------------------------------------------------------
+-- Copyright (c) 2013, ETH Zurich.
+-- 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, Universitaetsstr. 6, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for /usr/vnode_map_test
+-- 
+--------------------------------------------------------------------------
+
+[ build application { target = "vnode_map_test",
+                      cFiles = [ "vnode_map_test.c" ]
+                    }
+]
+
diff --git a/usr/vnode_map_test/vnode_map_test.c b/usr/vnode_map_test/vnode_map_test.c
new file mode 100644 (file)
index 0000000..23c72ae
--- /dev/null
@@ -0,0 +1,329 @@
+/**
+ * \file
+ * \brief Test program for large page code
+ */
+
+/*
+ * Copyright (c) 2013, ETH Zurich.
+ * 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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <stdio.h>
+
+#define SAFE_VADDR (genvaddr_t)(8ULL<<39)
+#define SAFE_PMAP_ADDR (genvaddr_t)(9ULL<<39)
+// 2M
+#define DEFAULT_SIZE X86_64_LARGE_PAGE_SIZE
+
+static enum objtype type[] = {
+    ObjType_VNode_x86_64_pml4,
+    ObjType_VNode_x86_64_pdpt,
+    ObjType_VNode_x86_64_pdir,
+    ObjType_VNode_x86_64_ptable
+};
+
+// the offsets of the indices for the different page table levels
+static uint8_t offsets[] = { 39, 30, 21, 12 };
+
+static paging_x86_64_flags_t PAGE_DEFAULT_ACCESS =
+    PTABLE_USER_SUPERVISOR |
+    PTABLE_EXECUTE_DISABLE |
+    PTABLE_READ_WRITE;
+    
+static vregion_flags_t PMAP_DEFAULT_ACCESS =
+    VREGION_FLAGS_READ_WRITE;
+
+static void test_region(uint32_t *buf, size_t size)
+{
+    int j = 0;
+    for (int i = 0; i < size; i+=4) {
+        j+=4;
+        if( (size-j) < 200)
+        {
+        printf("%i, ", i);
+        }
+        
+        buf[i/4] = i;
+    }
+    for (int i = 0; i < size; i+=4) {
+        assert(buf[i/4] == i);
+    }
+    printf("\n\n");
+
+}
+
+
+int main(void)
+{
+    struct capref frame, smallframe, vnodes[4];
+    size_t bytes = DEFAULT_SIZE;
+    size_t bits = 4*1024;
+    errval_t err;
+
+    //get 4k frame cap
+    err = frame_alloc(&smallframe, bits, &bits);
+    assert(err_is_ok(err));
+    assert(bits >= 4*1024);
+    // get 2M frame cap
+    err = frame_alloc(&frame, bytes, &bytes);
+    assert(err_is_ok(err));
+    assert(bytes >= DEFAULT_SIZE);
+
+    // check that we have the necessary ptables (note: this is not how you
+    // should do this cf. with pmap_target.c
+    // setup reference to pml4 capability
+    vnodes[0] = (struct capref) {
+        .cnode = cnode_page,
+        .slot  = 0,
+    };
+    // note we start iterating on 1, because we're using index 0 as the
+    // well-known pml4 capref
+    for (int i = 1; i < sizeof(type) / sizeof(type[0]); i++) {
+        err = slot_alloc(&vnodes[i]);
+        assert(err_is_ok(err));
+        printf("creating vnode for level %d, type %d\n", i, type[i]);
+        err = vnode_create(vnodes[i], type[i]);
+        assert(err_is_ok(err));
+        uint32_t slot = (SAFE_VADDR >> offsets[i-1]) & 0x1f;
+        printf("mapping into slot %d on level %d\n", slot, i-1);
+        err = vnode_map(vnodes[i-1], vnodes[i], slot, PTABLE_ACCESS_DEFAULT, 0, 1);
+        if (err_is_fail(err)) {
+            // this means we already have a page table for this level
+            // XXX: right now we've chosen the SAFE_VADDR such that we don't have
+            // any intermediate level page tables so we don't need to worry
+            // about this case
+            printf("there was a page table already?\n");
+            printf("vnode_map: %s\n", err_getstring(err));
+            exit(1);
+        }
+    }
+    
+// map as 4k and 2m frames with vnode_map
+// used to test the kernel code
+#if 1
+    //printf("start 4k vnode map");
+    err = vnode_map(vnodes[3], smallframe, (SAFE_VADDR>>offsets[3])&0x1f,
+            PAGE_DEFAULT_ACCESS, 0, 4*1024 / X86_64_BASE_PAGE_SIZE);
+#endif
+#if 0
+    if (err_is_fail(err)) {
+        printf("error in vnode_map: %s\n", err_getstring(err));
+        exit(1);
+    }
+
+    test_region((uint32_t*)SAFE_VADDR, 4*1024);
+
+    // FROM HERE: unmap and try to map as large page
+
+    // unmap frame
+    printf("start 4k unmap\n");
+    err = vnode_unmap(vnodes[3], smallframe, (SAFE_VADDR>>offsets[3])&0x1f,
+            4*1024 / X86_64_BASE_PAGE_SIZE);
+    if (err_is_fail(err)) {
+        printf("vnode_unmap: %s\n", err_getstring(err));
+    }
+    assert(err_is_ok(err));
+    // unmap level 3 page table
+    err = vnode_unmap(vnodes[2], vnodes[3], SAFE_VADDR>>offsets[2]&0x1f, 1);
+    assert(err_is_ok(err));
+    
+    // map as 2M large page
+    printf("start 2m vnodemap\n");
+    err = vnode_map(vnodes[2], frame, SAFE_VADDR>>offsets[2]&0x1f,
+            PAGE_DEFAULT_ACCESS, 0, DEFAULT_SIZE / X86_64_LARGE_PAGE_SIZE);
+    if (err_is_fail(err)) {
+        printf("error in vnode_map: %s\n", err_getstring(err));
+        exit(1);
+    }
+
+    test_region((uint32_t*)SAFE_VADDR, DEFAULT_SIZE);
+    
+    err = vnode_unmap(vnodes[2], frame, SAFE_VADDR>>offsets[2]&0x1f, DEFAULT_SIZE / X86_64_LARGE_PAGE_SIZE);
+    if (err_is_fail(err)) {
+        printf("vnode_unmap: %s\n", err_getstring(err));
+    }
+    assert(err_is_ok(err));
+#endif
+    
+    struct pmap *pmap;
+    
+//normal page via pmap interface
+// used to test if 4k code still works
+// (although this would break the whole barrelfish boot)
+#if 0
+    printf("\n\nstart 4k map with pmap\n");
+    bits = 4*1024;
+    printf("    frame_alloc\n");
+    err = frame_alloc(&smallframe, bits, &bits);
+    assert(err_is_ok(err));
+    assert(bits >= 4*1024);
+    printf("    get pmap\n");
+    pmap = get_current_pmap();
+    
+    
+    printf("    map\n");
+    err = pmap->f.map(pmap, SAFE_PMAP_ADDR, smallframe, 0, bits, PMAP_DEFAULT_ACCESS, NULL, &bits);
+    if (err_is_fail(err))
+    {
+        printf("error in pmap: %s\n", err_getstring(err));
+    }
+    test_region((uint32_t*)SAFE_PMAP_ADDR, 4*1024);
+    
+    printf("\tunmap\n");
+    err = pmap->f.unmap(pmap, SAFE_PMAP_ADDR, bits, NULL);
+#endif
+
+    
+//large page via pmap interface
+// used to test the 2M pages on a safe address
+// looped 10 times to see if unmap does work
+#if 0
+    printf("start 2m map with pmap\n");
+    bytes = DEFAULT_SIZE;
+    err = frame_alloc(&frame, bytes, &bytes);
+    assert(err_is_ok(err));
+    assert(bytes >= DEFAULT_SIZE);
+    
+    pmap = get_current_pmap();
+
+    for(int i = 0; i<10; ++i){
+        printf("map %i\n", i);
+        err = pmap->f.map(pmap, SAFE_PMAP_ADDR, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+        if (err_is_fail(err))
+        {
+            printf("error in pmap: %s\n", err_getstring(err));
+            exit(1);
+        }
+    
+        test_region((uint32_t*)SAFE_PMAP_ADDR, DEFAULT_SIZE);
+    
+        err = pmap->f.unmap(pmap, SAFE_PMAP_ADDR, bytes, NULL);
+        if (err_is_fail(err))
+        {
+            printf("error in unmap: %s\n", err_getstring(err));
+            exit(1);
+        } 
+    }//end for
+#endif
+
+
+        struct memobj a;
+        genvaddr_t address;
+        
+//test determine_addr_raw as address obtainer
+// mapping 4k page
+#if 0
+    printf("determine_addr 4k\n");
+    bits = 4*1024;
+    err = frame_alloc(&smallframe, bits, &bits);
+    assert(err_is_ok(err));
+    assert(bits >= 4*1024);
+    
+    //determine address
+    a.size = bits;
+    address = 0;
+    pmap = get_current_pmap();
+    err = pmap->f.determine_addr_raw(pmap, a.size, BASE_PAGE_SIZE, &address);
+    printf("address: %lx\n", (unsigned long) address);
+    if (err_is_fail(err))
+    {
+        printf("error in determine_addr: %s\n", err_getstring(err));
+        exit(1);
+    }
+    
+    err = pmap->f.map(pmap, address, smallframe, 0, bits, PMAP_DEFAULT_ACCESS, NULL, &bits);
+    if (err_is_fail(err))
+    {
+        printf("error in pmap: %s\n", err_getstring(err));
+        exit(1);
+    }
+    test_region((uint32_t*)address, 4*1024);
+#endif
+
+
+// determine_addr_raw for 2m pages
+// for loop inserted currently
+// this was the only way multiple large pages could be accessed
+// no longer necessary
+#if 0
+    printf("determine_addr 2m\n");
+    genvaddr_t* addresses = malloc(200*sizeof(genvaddr_t));
+for(int i = 0; i<200; ++i){
+    bytes = DEFAULT_SIZE;
+    err = frame_alloc(&frame, bytes, &bytes);
+    assert(err_is_ok(err));
+    assert(bytes >= DEFAULT_SIZE);
+    
+    a.size = bytes;
+    printf("a.size: %x, %i\n", (unsigned int) a.size, (unsigned int) a.size);
+    address = 0;
+    pmap = get_current_pmap();
+    err = pmap->f.determine_addr_raw(pmap, a.size, LARGE_PAGE_SIZE, &address);
+    printf("address: %x\n", (unsigned int) address);
+    if(err_is_fail(err))
+    {
+        printf("error in determine_addr: %s\n", err_getstring(err));
+        exit(1);
+    }
+    
+    err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+    if (err_is_fail(err))
+    {
+        printf("error in pmap: %s\n", err_getstring(err));
+        exit(1);
+    }
+    addresses[i] = address;
+}
+for(int i = 0; i<200; ++i){
+    test_region((uint32_t*)addresses[i], DEFAULT_SIZE);
+}
+#endif
+
+    
+// multiple large pages with one go
+// the for loop is to test unmap
+#if 1
+    printf("multiple 2m\n");
+    bytes = 10*DEFAULT_SIZE;
+    err = frame_alloc(&frame, bytes, &bytes);
+    assert(err_is_ok(err));
+    assert(bytes >= 10*DEFAULT_SIZE);
+    
+    a.size = bytes;
+    printf("a.size: %x, %i\n", (unsigned int) a.size, (unsigned int) a.size);
+    address = 0;
+    pmap = get_current_pmap();
+    err = pmap->f.determine_addr_raw(pmap, a.size, LARGE_PAGE_SIZE, &address);
+    printf("address: %x\n", (unsigned int) address);
+    if(err_is_fail(err))
+    {
+        printf("error in determine_addr: %s\n", err_getstring(err));
+        exit(1);
+    }
+for (int i=0; i<10; ++i) {  
+printf("map %i\n", i);  
+    err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+    if (err_is_fail(err))
+    {
+        printf("error in pmap: %s\n", err_getstring(err));
+        exit(1);
+    }
+
+    test_region((uint32_t*)address, 10*DEFAULT_SIZE);
+
+    err = pmap->f.unmap(pmap, address, bytes, NULL);
+    if (err_is_fail(err))
+    {
+        printf("error in unmap: %s\n", err_getstring(err));
+        exit(1);
+    } 
+}//endfor
+#endif   
+    printf("exited successfully\n");
+    return 0;
+}