Merge large page support code.
authorSimon Gerber <simon.gerber@inf.ethz.ch>
Mon, 4 May 2015 09:31:03 +0000 (11:31 +0200)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Mon, 4 May 2015 09:31:03 +0000 (11:31 +0200)
This code was originally written by Andreas Dillier as a deliverable for his
Bachelor thesis at ETH Zurich in 2013. Simon Gerber then fixed and extended
the implementation of large page support while employed by HP Labs in summer
2014.
The files that contain code written while Simon was employed by HP Labs have
updated copyright notices and the relevant commits are marked with
"Signed-off-by: Simon Gerber <simon.gerber@hp.com>" (as is this merge).

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

45 files changed:
errors/errno.fugu
hake/Config.hs.template
hake/symbolic_targets.mk
include/arch/x86_64/barrelfish_kpi/paging_arch.h
include/barrelfish/morecore.h
include/barrelfish/pmap.h
include/barrelfish/vregion.h
include/barrelfish/vspace_common.h
include/barrelfish/vspace_mmu_aware.h
include/target/x86_32/barrelfish_kpi/paging_target.h
include/target/x86_64/barrelfish_kpi/paging_target.h
kernel/arch/armv7/paging.c
kernel/arch/x86_32/page_mappings_arch.c
kernel/arch/x86_32/paging.c
kernel/arch/x86_32/startup_arch.c
kernel/arch/x86_64/page_mappings_arch.c
kernel/include/target/x86_64/paging_kernel_target.h
kernel/paging_generic.c
lib/barrelfish/Hakefile
lib/barrelfish/arch/arm/pmap_arch.c
lib/barrelfish/include/target/x86/pmap_x86.h
lib/barrelfish/init.c
lib/barrelfish/morecore.c
lib/barrelfish/slot_alloc/multi_slot_alloc.c
lib/barrelfish/target/x86/pmap_x86.c
lib/barrelfish/target/x86_32/pmap_target.c
lib/barrelfish/target/x86_64/pmap_target.c
lib/barrelfish/vspace/memobj_anon.c
lib/barrelfish/vspace/mmu_aware.c
lib/barrelfish/vspace/utils.c
lib/barrelfish/vspace/vregion.c
usr/bench/largepage/Hakefile [new file with mode: 0644]
usr/bench/largepage/largepage_64_bench.c [new file with mode: 0644]
usr/tests/argtest/Hakefile [new file with mode: 0644]
usr/tests/argtest/argtest.c [new file with mode: 0644]
usr/tests/large_page/Hakefile [new file with mode: 0644]
usr/tests/large_page/malloc_test.c [new file with mode: 0644]
usr/tests/large_page/map_test.c [new file with mode: 0644]
usr/tests/large_page/map_test_32.c [new file with mode: 0644]
usr/tests/nkm/Hakefile
usr/tests/nkm/invalid_mappings.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 44dcc4c..a69ffbd 100755 (executable)
@@ -1,6 +1,7 @@
 
 /*
  * Copyright (c) 2009, 2010, 2011, 2012, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
@@ -269,6 +270,8 @@ errors libbarrelfish LIB_ERR_ {
     failure PMAP_ADDR_NOT_FREE "The requested address range is not free",
     failure PMAP_FIND_VNODE   "vnode not found",
     failure PMAP_EXISTING_MAPPING "Cannot replace existing mapping, unmap first",
+    failure PMAP_FRAME_SIZE "Given Frame to small to fulfil mapping request",
+    failure PMAP_FRAME_IDENTIFY "Frame could not be identified",
 
     failure OUT_OF_VIRTUAL_ADDR  "Out of virtual address",
 
index bf428da..e8dc4dc 100644 (file)
@@ -1,5 +1,6 @@
 --------------------------------------------------------------------------
 -- Copyright (c) 2007-2010, 2012, 2013, ETH Zurich.
+-- Copyright (c) 2014, HP Labs.
 -- All rights reserved.
 --
 -- This file is distributed under the terms in the attached LICENSE file.
@@ -43,6 +44,13 @@ newlib_malloc :: String
 --newlib_malloc = "dlmalloc" -- use dlmalloc
 newlib_malloc = "oldmalloc"
 
+-- Configure pagesize for libbarrelfish's morecore implementation
+-- x86_64 accepts "small", "large", and "huge" for 4kB, 2MB and 1GB pages
+-- respectively. x86_32 accepts "small" and "large" for 4kB and 2MB/4MB pages
+-- respectively. All other architectures default to their default page size.
+morecore_pagesize :: String
+morecore_pagesize = "large"
+
 -- Use a frame pointer
 use_fp :: Bool
 use_fp = True
index 7f81837..bc2d803 100644 (file)
@@ -228,6 +228,7 @@ MODULES_x86_64= \
        sbin/slideshow \
        sbin/vbe \
        sbin/vmkitmon \
+       sbin/vnode_map_test \
        sbin/webserver \
        sbin/routing_setup \
        sbin/bcached \
index 02d8113..546ee9f 100644 (file)
@@ -4,12 +4,12 @@
  */
 
 /*
- * Copyright (c) 2010, ETH Zurich.
+ * Copyright (c) 2010-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.
+ * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
  */
 
 #ifndef ARCH_X86_64_BARRELFISH_KPI_PAGING_H
 #define LARGE_PAGE_MASK      X86_64_LARGE_PAGE_MASK
 #define LARGE_PAGE_OFFSET    X86_64_LARGE_PAGE_OFFSET
 
+#define HUGE_PAGE_BITS      X86_64_HUGE_PAGE_BITS
+#define HUGE_PAGE_SIZE      X86_64_HUGE_PAGE_SIZE
+#define HUGE_PAGE_MASK      X86_64_HUGE_PAGE_MASK
+#define HUGE_PAGE_OFFSET    X86_64_HUGE_PAGE_OFFSET
+
 /**
  * Bits within the various page directories and tables.
  */
index 37bcf76..5c957f1 100644 (file)
@@ -5,11 +5,12 @@
 
 /*
  * Copyright (c) 2007, 2008, 2009, 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.
  */
 
 #ifndef BARRELFISH_MORECORE_H
@@ -19,8 +20,9 @@
 
 __BEGIN_DECLS
 
-errval_t morecore_init(void);
+errval_t morecore_init(size_t alignment);
 void morecore_use_optimal(void);
+errval_t morecore_reinit(void);
 
 __END_DECLS
 
index c554ed6..e425a18 100644 (file)
@@ -4,12 +4,12 @@
  */
 
 /*
- * Copyright (c) 2009, ETH Zurich.
+ * Copyright (c) 2009-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.
+ * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
  */
 
 #ifndef LIBBARRELFISH_PMAP_H
@@ -20,6 +20,8 @@ struct pmap;
 struct pmap_funcs {
     errval_t (*determine_addr)(struct pmap *pmap, struct memobj *memobj,
                                size_t alignment, genvaddr_t *vaddr);
+    errval_t (*determine_addr_raw)(struct pmap *pmap, size_t size,
+                                   size_t alignment, genvaddr_t *vaddr);
     errval_t (*map)(struct pmap* pmap, genvaddr_t vaddr, struct capref frame,
                     size_t offset, size_t size, vregion_flags_t flags,
                     size_t *retoffset, size_t *retsize);
index f0d4c92..6d2ef56 100644 (file)
@@ -5,11 +5,12 @@
 
 /*
  * Copyright (c) 2009, 2010, 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.
  */
 
 #ifndef LIBBARRELFISH_VREGION_H
@@ -26,7 +27,10 @@ __BEGIN_DECLS
 #define VREGION_FLAGS_NOCACHE  0x08 // Caching disabled
 #define VREGION_FLAGS_MPB      0x10 // Message passing buffer
 #define VREGION_FLAGS_GUARD    0x20 // Guard page
-#define VREGION_FLAGS_MASK     0x2f // Mask of all individual VREGION_FLAGS
+// XXX: figure out how to do this arch-independent(?) -SG, 2014-06-16
+#define VREGION_FLAGS_LARGE    0x40 // Map large pages, if possible
+#define VREGION_FLAGS_HUGE     0x80 // Map huge pages, if possible
+#define VREGION_FLAGS_MASK     0xff // Mask of all individual VREGION_FLAGS
 
 #define VREGION_FLAGS_READ_WRITE \
     (VREGION_FLAGS_READ | VREGION_FLAGS_WRITE)
index 804838b..6b6b899 100644 (file)
@@ -5,6 +5,7 @@
 
 /*
  * 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.
@@ -54,6 +55,11 @@ errval_t vspace_map_one_frame_attr(void **retaddr, size_t size,
                                    struct capref frame, vregion_flags_t flags,
                                    struct memobj **retmemobj,
                                    struct vregion **retvregion);
+errval_t vspace_map_one_frame_attr_aligned(void **retaddr, size_t size,
+                                   struct capref frame, vregion_flags_t flags,
+                                   size_t alignment,
+                                   struct memobj **retmemobj,
+                                   struct vregion **retvregion);
 errval_t vspace_map_one_frame(void **retaddr, size_t size, struct capref frame,
                               struct memobj **retmemobj,
                               struct vregion **retvregion);
index 42ffc0b..064231b 100644 (file)
@@ -5,11 +5,12 @@
 
 /*
  * Copyright (c) 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.
  */
 
 #ifndef LIBBARRELFISH_VSPACE_MMU_AWARE_H
@@ -28,6 +29,7 @@ struct vspace_mmu_vregion_list {
 /// Struct to support mmu_aware memory management
 struct vspace_mmu_aware {
     size_t size;
+    size_t alignment;
     size_t consumed;
     struct vregion vregion;           ///< Needs just one vregion
     struct memobj_anon memobj;        ///< Needs just one memobj
@@ -36,6 +38,11 @@ struct vspace_mmu_aware {
 };
 
 errval_t vspace_mmu_aware_init(struct vspace_mmu_aware *state, size_t size);
+errval_t vspace_mmu_aware_init_aligned(struct vspace_mmu_aware *state,
+                                       size_t size, size_t alignment,
+                                       vregion_flags_t flags);
+errval_t vspace_mmu_aware_reset(struct vspace_mmu_aware *state,
+                                struct capref frame, size_t size);
 errval_t vspace_mmu_aware_map(struct vspace_mmu_aware *state,
                               struct capref frame, size_t req_size,
                               void **retbuf, size_t *retsize);
index e511c3a..d82de5d 100644 (file)
@@ -4,12 +4,12 @@
  */
 
 /*
- * Copyright (c) 2010, ETH Zurich.
+ * Copyright (c) 2010-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.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
  */
 
 #ifndef TARGET_X86_32_BARRELFISH_KPI_PAGING_H
@@ -72,6 +72,8 @@ typedef uint32_t paging_x86_32_flags_t;
 #define X86_32_PDPTE_MASK              3
 #define X86_32_PDPTE_CLEAR             0
 
+#define X86_32_PDIR_SIZE           512
+
 #define X86_32_PTABLE_SIZE         512     /**< Page directory/table size */
 #define X86_32_PTABLE_MASK         0x1ff   /**< Page dir/table address mask */
 #define X86_32_PTABLE_CLEAR        0       /**< Bitmap of a clear table entry */
index 29001a7..98c8d88 100644 (file)
@@ -4,12 +4,13 @@
  */
 
 /*
- * Copyright (c) 2010, ETH Zurich.
+ * Copyright (c) 2010-2013 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.
  */
 
 #ifndef TARGET_X86_64_BARRELFISH_KPI_PAGING_H
@@ -21,16 +22,22 @@ typedef uint64_t paging_x86_64_flags_t;
 
 /** The system's base page size is 4kB */
 #define X86_64_BASE_PAGE_BITS                  12
-#define X86_64_BASE_PAGE_SIZE                  0x1000
+#define X86_64_BASE_PAGE_SIZE                  (1<<X86_64_BASE_PAGE_BITS)
 #define X86_64_BASE_PAGE_MASK                  (X86_64_BASE_PAGE_SIZE - 1)
 #define X86_64_BASE_PAGE_OFFSET(a)             ((a) & X86_64_BASE_PAGE_MASK)
 
 /** The system's large page size is 2MB */
 #define X86_64_LARGE_PAGE_BITS                  21
-#define X86_64_LARGE_PAGE_SIZE                  0x200000
+#define X86_64_LARGE_PAGE_SIZE                  (1<<X86_64_LARGE_PAGE_BITS)
 #define X86_64_LARGE_PAGE_MASK                  (X86_64_LARGE_PAGE_SIZE - 1)
 #define X86_64_LARGE_PAGE_OFFSET(a)             ((a) & X86_64_LARGE_PAGE_MASK)
 
+/** The system's huge page size is 1GB */
+#define X86_64_HUGE_PAGE_BITS                  30
+#define X86_64_HUGE_PAGE_SIZE                  (1<<X86_64_HUGE_PAGE_BITS)
+#define X86_64_HUGE_PAGE_MASK                  (X86_64_HUGE_PAGE_SIZE - 1)
+#define X86_64_HUGE_PAGE_OFFSET(a)             ((a) & X86_64_HUGE_PAGE_MASK)
+
 /**
  * Bits within the various page directories and tables.
  */
@@ -45,7 +52,9 @@ typedef uint64_t paging_x86_64_flags_t;
 #define X86_64_PTABLE_READ_WRITE       (((paging_x86_64_flags_t)1) << 1)
 #define X86_64_PTABLE_PRESENT          (((paging_x86_64_flags_t)1) << 0)
 
-#define X86_64_PTABLE_SIZE         512     /**< Page directory/table size */
+#define X86_64_PTABLE_BITS         9       /**< Page directory/table size in bits */
+/** Page directory/table size */
+#define X86_64_PTABLE_SIZE         (1UL<<X86_64_PTABLE_BITS)
 #define X86_64_PTABLE_MASK         0x1ff   /**< Page dir/table address mask */
 #define X86_64_PTABLE_CLEAR        0       /**< Bitmap of a clear table entry */
 
index 5195932..d2ebf62 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * Copyright (c) 2009 - 2012 ETH Zurich.
+ * Copyright (c) 2009 - 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.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
  */
 
 #include <kernel.h>
@@ -80,7 +80,73 @@ caps_map_l1(struct capability* dest,
     }
 
     if (src->type != ObjType_VNode_ARM_l2) {
-        panic("oops: wrong src type");
+        //large page mapping goes here
+        printf("kernel large page\n");
+        //panic("oops: wrong src type");
+        assert(0 == (kpi_paging_flags & ~KPI_PAGING_FLAGS_MASK));
+
+        // ARM L1 has 4K entries, but we treat it as if it had 1K
+        if (slot >= (256 * 4)) {
+            panic("oops: slot >= (256 * 4)");
+            return SYS_ERR_VNODE_SLOT_INVALID;
+        }
+
+        if (src->type != ObjType_Frame && src->type != ObjType_DevFrame) {
+            panic("oops: src->type != ObjType_Frame && src->type != ObjType_DevFrame");
+            return SYS_ERR_WRONG_MAPPING;
+        }
+
+        // check offset within frame
+        if ((offset + BYTES_PER_SECTION > get_size(src)) ||
+            ((offset % BYTES_PER_SECTION) != 0)) {
+            panic("oops: frame offset invalid");
+            return SYS_ERR_FRAME_OFFSET_INVALID;
+        }
+
+        // check mapping does not overlap leaf page table
+        if (slot + pte_count > (256 * 4)) {
+            return SYS_ERR_VM_MAP_SIZE;
+        }
+
+        // Destination
+        lpaddr_t dest_lpaddr = gen_phys_to_local_phys(get_address(dest));
+        lvaddr_t dest_lvaddr = local_phys_to_mem(dest_lpaddr);
+
+        union arm_l1_entry* entry = (union arm_l1_entry*)dest_lvaddr + slot;
+        if (entry->invalid.type != L1_TYPE_INVALID_ENTRY) {
+            panic("Remapping valid page.");
+        }
+
+        lpaddr_t src_lpaddr = gen_phys_to_local_phys(get_address(src) + offset);
+        if ((src_lpaddr & (LARGE_PAGE_SIZE - 1))) {
+            panic("Invalid target");
+        }
+
+        struct cte *src_cte = cte_for_cap(src);
+        src_cte->mapping_info.pte_count = pte_count;
+        src_cte->mapping_info.pte = dest_lpaddr;
+        src_cte->mapping_info.offset = offset;
+
+        for (int i = 0; i < pte_count; i++) {
+            entry->raw = 0;
+
+            entry->section.type = L1_TYPE_SECTION_ENTRY;
+            entry->section.bufferable = 1;
+            entry->section.cacheable = (kpi_paging_flags & KPI_PAGING_FLAGS_NOCACHE)? 0: 1;
+            entry->section.ap10 = (kpi_paging_flags & KPI_PAGING_FLAGS_READ)? 2:0;
+            entry->section.ap10 |= (kpi_paging_flags & KPI_PAGING_FLAGS_WRITE)? 3:0;
+            entry->section.ap2 = 0;
+            entry->section.base_address = (src_lpaddr + i * BYTES_PER_SECTION) >> 12;
+
+            entry++;
+
+            debug(SUBSYS_PAGING, "L2 mapping %08"PRIxLVADDR"[%"PRIuCSLOT"] @%p = %08"PRIx32"\n",
+                   dest_lvaddr, slot, entry, entry->raw);
+        }
+
+        // Flush TLB if remapping.
+        cp15_invalidate_tlb();
+        return SYS_ERR_OK;
         return SYS_ERR_WRONG_MAPPING;
     }
 
index ad740cc..17e310c 100644 (file)
@@ -4,12 +4,13 @@
  */
 
 /*
- * Copyright (c) 2010, ETH Zurich.
+ * Copyright (c) 2010-2013 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 <kernel.h>
@@ -70,12 +71,13 @@ static errval_t x86_32_pdir(struct capability *dest, cslot_t slot,
                             struct capability * src, uintptr_t flags,
                             uintptr_t offset, uintptr_t pte_count)
 {
+    //printf("x86_32_pdir\n");
     if (slot >= X86_32_PTABLE_SIZE) { // Slot within page table
         return SYS_ERR_VNODE_SLOT_INVALID;
     }
 
-    if (pte_count > 1) { // disallow more than one page at a time
-        // XXX: this prevents mapping multiple superpages at a time
+    if (slot + pte_count > X86_32_PTABLE_SIZE) {
+        // check that mapping fits page directory
         return SYS_ERR_VM_MAP_SIZE;
     }
 
@@ -85,6 +87,59 @@ static errval_t x86_32_pdir(struct capability *dest, cslot_t slot,
     }
 #endif
 
+    // large page code
+    if(src->type == ObjType_Frame || src->type == ObjType_DevFrame)
+    {
+        cslot_t last_slot = slot + pte_count;
+
+        // check offset within frame
+        if (offset + pte_count * X86_32_LARGE_PAGE_SIZE > get_size(src)) {
+            return SYS_ERR_FRAME_OFFSET_INVALID;
+        }
+
+        /* Calculate page access protection flags */
+        // Get frame cap rights
+        paging_x86_32_flags_t flags_large =
+            paging_x86_32_cap_to_page_flags(src->rights);
+        // Mask with provided access rights mask
+        flags_large = paging_x86_32_mask_attrs(flags_large, X86_32_PTABLE_ACCESS(flags));
+        // Add additional arch-specific flags
+        flags_large |= X86_32_PTABLE_FLAGS(flags);
+        // Unconditionally mark the page present
+        flags_large |= X86_32_PTABLE_PRESENT;
+
+        // Convert destination base address
+        genpaddr_t dest_gp   = get_address(dest);
+        lpaddr_t dest_lp     = gen_phys_to_local_phys(dest_gp);
+        lvaddr_t dest_lv     = local_phys_to_mem(dest_lp);
+        // Convert source base address
+        genpaddr_t src_gp   = get_address(src);
+        lpaddr_t src_lp     = gen_phys_to_local_phys(src_gp);
+        // Set metadata
+        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;
+
+        for (; slot < last_slot; slot++, offset += X86_32_LARGE_PAGE_SIZE) {
+            union x86_32_ptable_entry *entry =
+                (union x86_32_ptable_entry *)dest_lv + slot;
+
+            /* FIXME: Flush TLB if the page is already present
+             * in the meantime, since we don't do this, we just assert that
+             * we never reuse a VA mapping */
+            if (X86_32_IS_PRESENT(entry)) {
+                printf("Trying to map into an already present page NYI.\n");
+                return SYS_ERR_VNODE_SLOT_INUSE;
+            }
+
+            // Carry out the page mapping
+            paging_x86_32_map_large(entry, src_lp + offset, flags_large);
+        }
+
+        return SYS_ERR_OK;
+    }
+
     if (src->type != ObjType_VNode_x86_32_ptable) { // Right mapping
         return SYS_ERR_WRONG_MAPPING;
     }
@@ -117,6 +172,7 @@ static errval_t x86_32_ptable(struct capability *dest, cslot_t slot,
                               struct capability * src, uintptr_t uflags,
                               uintptr_t offset, uintptr_t pte_count)
 {
+    //printf("x86_32_ptable\n");
     if (slot >= X86_32_PTABLE_SIZE) { // Slot within page table
         return SYS_ERR_VNODE_SLOT_INVALID;
     }
@@ -359,7 +415,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);
@@ -407,9 +464,9 @@ void paging_dump_tables(struct dcb *dispatcher)
 
 #ifdef CONFIG_PAE
     // loop over pdpt entries
-    for (int pdir_index = 0; pdir_index < X86_64_PDPTE_SIZE; pdir_index++) {
+    for (int pdir_index = 0; pdir_index < X86_32_PDPTE_SIZE; pdir_index++) {
         // get pdir
-        union x86_32_pdpte_entry *pdir = (union x86_64_pdir_entry *)root_pt + pdir_index;
+        union x86_32_pdpte_entry *pdir = (union x86_32_pdpte_entry *)root_pt + pdir_index;
         if (!pdir->raw) { continue; }
         genpaddr_t pdir_gp = pdir->d.base_addr << BASE_PAGE_BITS;
         lvaddr_t pdir_lv = local_phys_to_mem(gen_phys_to_local_phys(pdir_gp));
@@ -418,10 +475,20 @@ void paging_dump_tables(struct dcb *dispatcher)
         lvaddr_t pdir_lv = root_pt;
 #endif
 
-        for (int ptable_index = 0; ptable_index < X86_32_PDIR_SIZE; ptable_index++) {
+        // only go to 512 because upper half of address space is kernel space
+        // (1:1 mapped)
+        // TODO: figure out what we need to do here for PAE
+        for (int ptable_index = 0; ptable_index < 512; ptable_index++) {
             // get ptable
             union x86_32_pdir_entry *ptable = (union x86_32_pdir_entry *)pdir_lv + ptable_index;
+            union x86_32_ptable_entry *large = (union x86_32_ptable_entry *)ptable;
             if (!ptable->raw) { continue; }
+            if (large->large.always1) {
+                // large page
+                genpaddr_t paddr = large->large.base_addr << X86_32_LARGE_PAGE_BITS;
+                printf("%d.%d: 0x%"PRIxGENPADDR"\n", pdir_index,
+                        ptable_index, paddr);
+            }
             genpaddr_t ptable_gp = ptable->d.base_addr << BASE_PAGE_BITS;
             lvaddr_t ptable_lv = local_phys_to_mem(gen_phys_to_local_phys(ptable_gp));
 
index 9d07890..3ef2d4c 100644 (file)
@@ -4,12 +4,12 @@
  */
 
 /*
- * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
+ * Copyright (c) 2007-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.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
  */
 
 #include <kernel.h>
@@ -165,7 +165,7 @@ static int paging_x86_32_map_mem(lpaddr_t base, size_t size, uint64_t bitmap)
         union x86_32_ptable_entry *pdir_base =
             &mem_pdir[X86_32_PDPTE_BASE(addr)][X86_32_PDIR_BASE(vaddr)];
 #else
-        union x86_32_pdir_entry *pdir_base = &pdir[X86_32_PDIR_BASE(vaddr)];
+        union x86_32_pdir_entry *pdir_base = (union x86_32_pdir_entry*) &pdir[X86_32_PDIR_BASE(vaddr)];
 #       ifndef CONFIG_PSE
         union x86_32_ptable_entry *ptable_base =
             &mem_ptable[X86_32_PDIR_BASE(addr)][X86_32_PTABLE_BASE(vaddr)];
@@ -179,16 +179,16 @@ static int paging_x86_32_map_mem(lpaddr_t base, size_t size, uint64_t bitmap)
         }
 
 #ifdef CONFIG_PAE
-        debug(SUBSYS_PAGING, "Mapping 2M page: vaddr = 0x%x, addr = 0x%x, "
-              "PDPTE_BASE = %u, PDIR_BASE = %u -- ", vaddr,
+        debug(SUBSYS_PAGING, "Mapping 2M page: vaddr = 0x%"PRIxLVADDR", addr = 0x%"PRIxLVADDR", "
+              "PDPTE_BASE = %"PRIuLPADDR", PDIR_BASE = %"PRIuLPADDR" -- ", vaddr,
               addr, X86_32_PDPTE_BASE(vaddr), X86_32_PDIR_BASE(vaddr));
         mapit(pdpte_base, pdir_base, addr, bitmap);
 #else
 #       ifdef CONFIG_PSE
-        debug(SUBSYS_PAGING, "Mapping 4M page: vaddr = 0x%x, addr = 0x%x, "
-              "PDIR_BASE = %u -- ", vaddr,
+        debug(SUBSYS_PAGING, "Mapping 4M page: vaddr = 0x%"PRIxLVADDR", addr = 0x%"PRIxLVADDR", "
+              "PDIR_BASE = %"PRIuLPADDR" -- ", vaddr,
               addr, X86_32_PDIR_BASE(vaddr));
-        mapit(pdir_base, addr, bitmap);
+        mapit((union x86_32_ptable_entry*)pdir_base, addr, bitmap);
 #       else
         debug(SUBSYS_PAGING, "Mapping 4K page: vaddr = 0x%"PRIxLVADDR", "
               "addr = 0x%"PRIxLVADDR", "
@@ -236,16 +236,16 @@ lvaddr_t paging_x86_32_map_special(lpaddr_t base, size_t size, uint64_t bitmap)
         union x86_32_ptable_entry *pdir_base =
             &mem_pdir[X86_32_PDPTE_BASE(mem_to_local_phys(vaddr))][X86_32_PDIR_BASE(vaddr)];
 
-        debug(SUBSYS_PAGING, "Mapping 2M device page: vaddr = 0x%x, addr = 0x%x, "
-              "PDPTE_BASE = %u, PDIR_BASE = %u -- ", vaddr,
+        debug(SUBSYS_PAGING, "Mapping 2M device page: vaddr = 0x%"PRIxLPADDR", addr = 0x%"PRIxLPADDR", "
+              "PDPTE_BASE = %"PRIxLPADDR", PDIR_BASE = %"PRIxLPADDR" -- ", vaddr,
               addr, X86_32_PDPTE_BASE(vaddr), X86_32_PDIR_BASE(vaddr));
         mapit(pdpte_base, pdir_base, addr, bitmap);
 #else
 #       ifdef CONFIG_PSE
         union x86_32_ptable_entry *pdir_base = &pdir[X86_32_PDIR_BASE(vaddr)];
 
-        debug(SUBSYS_PAGING, "Mapping 4M device page: vaddr = 0x%x, addr = 0x%x, "
-              "PDIR_BASE = %u -- ", vaddr, addr, X86_32_PDIR_BASE(vaddr));
+        debug(SUBSYS_PAGING, "Mapping 4M device page: vaddr = 0x%"PRIxLPADDR", addr = 0x%"PRIxLPADDR", "
+              "PDIR_BASE = %"PRIxLPADDR" -- ", vaddr, addr, X86_32_PDIR_BASE(vaddr));
         mapit(pdir_base, addr, bitmap);
 #       else
         union x86_32_pdir_entry *pdir_base = &pdir[X86_32_PDIR_BASE(vaddr)];
@@ -320,7 +320,7 @@ void paging_x86_32_make_good_pdpte(lpaddr_t base)
         (union x86_32_pdpte_entry *)local_phys_to_mem(base);
     int                 i;
 
-    debug(SUBSYS_PAGING, "Is now a PDPTE: table = 0x%x\n", base);
+    debug(SUBSYS_PAGING, "Is now a PDPTE: table = 0x%"PRIuLPADDR"\n", base);
     // Map memory
     for(i = X86_32_PDPTE_BASE(X86_32_MEMORY_OFFSET); i < X86_32_PDPTE_SIZE; i++) {
         newpdpte[i] = pdpte[i];
index 35ec739..80d4106 100644 (file)
@@ -4,12 +4,13 @@
  */
 
 /*
- * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
+ * Copyright (c) 2007-2013 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 <kernel.h>
@@ -119,9 +120,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%x, base = 0x%x, "
-              "PDPTE_BASE = %u, PDIR_BASE = %u, "
-              "PTABLE_BASE = %u -- ", vaddr, base, X86_32_PDPTE_BASE(vaddr),
+        debug(SUBSYS_PAGING, "Mapping 4K page: vaddr = 0x%"PRIxLVADDR
+              ", base = 0x%"PRIxLPADDR", PDPTE_BASE = %lu, PDIR_BASE = %lu, "
+              "PTABLE_BASE = %lu -- ", 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 faae519..ba63b71 100644 (file)
@@ -4,12 +4,13 @@
  */
 
 /*
- * Copyright (c) 2010, ETH Zurich.
+ * Copyright (c) 2010-2013 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 <kernel.h>
@@ -35,6 +36,7 @@ static errval_t x86_64_non_ptable(struct capability *dest, cslot_t slot,
                                   struct capability *src, uintptr_t flags,
                                   uintptr_t offset, size_t pte_count)
 {
+    //printf("page_mappings_arch:x86_64_non_ptable\n");
     if (slot >= X86_64_PTABLE_SIZE) { // Within pagetable
         return SYS_ERR_VNODE_SLOT_INVALID;
     }
@@ -50,6 +52,7 @@ static errval_t x86_64_non_ptable(struct capability *dest, cslot_t slot,
     }
 
     size_t page_size = 0;
+    paging_x86_64_flags_t flags_large = 0;
     switch (dest->type) {
         case ObjType_VNode_x86_64_pml4:
             if (src->type != ObjType_VNode_x86_64_pdpt) { // Right mapping
@@ -61,17 +64,48 @@ 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
-                printf("src type invalid\n");
-                return SYS_ERR_WRONG_MAPPING;
+                // TODO: check if the system allows 1GB mappings
+                page_size = X86_64_HUGE_PAGE_SIZE;
+                // check offset within frame
+                genpaddr_t off = offset;
+
+                if (off + pte_count * X86_64_HUGE_PAGE_SIZE > get_size(src)) {
+                    return SYS_ERR_FRAME_OFFSET_INVALID;
+                }
+                // Calculate page access protection flags /
+                // Get frame cap rights
+                flags_large = paging_x86_64_cap_to_page_flags(src->rights);
+                // Mask with provided access rights mask
+                flags_large = paging_x86_64_mask_attrs(flags, X86_64_PTABLE_ACCESS(flags));
+                // Add additional arch-specific flags
+                flags_large |= X86_64_PTABLE_FLAGS(flags);
+                // Unconditionally mark the page present
+                flags_large |= X86_64_PTABLE_PRESENT;
             }
             break;
         case ObjType_VNode_x86_64_pdir:
-            // TODO: superpage support, set page_size to SUPER_PAGE_SIZE
+            // superpage support
             if (src->type != ObjType_VNode_x86_64_ptable) { // Right mapping
-                printf("src type invalid\n");
-                return SYS_ERR_WRONG_MAPPING;
+                page_size = X86_64_LARGE_PAGE_SIZE;
+
+                // check offset within frame
+                genpaddr_t off = offset;
+              
+                if (off + pte_count * X86_64_LARGE_PAGE_SIZE > get_size(src)) {
+                    return SYS_ERR_FRAME_OFFSET_INVALID;
+                }
+                // Calculate page access protection flags /
+                // Get frame cap rights
+                flags_large = paging_x86_64_cap_to_page_flags(src->rights);
+                // Mask with provided access rights mask
+                flags_large = paging_x86_64_mask_attrs(flags, X86_64_PTABLE_ACCESS(flags));
+                // Add additional arch-specific flags
+                flags_large |= X86_64_PTABLE_FLAGS(flags);
+                // Unconditionally mark the page present
+                flags_large |= X86_64_PTABLE_PRESENT;
+
             }
             break;
         default:
@@ -102,10 +136,22 @@ static errval_t x86_64_non_ptable(struct capability *dest, cslot_t slot,
             // cleanup mapping info
             // TODO: cleanup already mapped pages
             memset(&src_cte->mapping_info, 0, sizeof(struct mapping_info));
+            printf("slot in use\n");
             return SYS_ERR_VNODE_SLOT_INUSE;
         }
 
-        paging_x86_64_map_table(entry, src_lp + offset);
+        // 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
+            paging_x86_64_map_large((union x86_64_ptable_entry *)entry, src_lp + offset, flags_large);
+        } else if (page_size == X86_64_HUGE_PAGE_SIZE) {
+            // a huge page is mapped
+            paging_x86_64_map_huge((union x86_64_ptable_entry *)entry, src_lp + offset, flags_large);
+        } else {
+            //a normal paging structure entry is mapped
+            paging_x86_64_map_table(entry, src_lp + offset);
+        }
     }
 
     return SYS_ERR_OK;
@@ -116,7 +162,9 @@ static errval_t x86_64_ptable(struct capability *dest, cslot_t slot,
                               struct capability *src, uintptr_t mflags,
                               uintptr_t offset, size_t pte_count)
 {
+    //printf("page_mappings_arch:x86_64_ptable\n");
     if (slot >= X86_64_PTABLE_SIZE) { // Within pagetable
+        printf("    vnode_invalid\n");
         return SYS_ERR_VNODE_SLOT_INVALID;
     }
 
@@ -436,10 +484,9 @@ void paging_dump_tables(struct dcb *dispatcher)
     lvaddr_t root_pt = local_phys_to_mem(dispatcher->vspace);
 
     // loop over pdpts
+    union x86_64_ptable_entry *pt;
     size_t kernel_pml4e = X86_64_PML4_BASE(X86_64_MEMORY_OFFSET);
-    printk(LOG_NOTE, "1st kernel pml4e: %zu\n", kernel_pml4e);
     for (int pdpt_index = 0; pdpt_index < kernel_pml4e; pdpt_index++) {
-
         union x86_64_pdir_entry *pdpt = (union x86_64_pdir_entry *)root_pt + pdpt_index;
         if (!pdpt->raw) { continue; }
         genpaddr_t pdpt_gp = pdpt->d.base_addr << BASE_PAGE_BITS;
@@ -448,15 +495,33 @@ void paging_dump_tables(struct dcb *dispatcher)
         for (int pdir_index = 0; pdir_index < X86_64_PTABLE_SIZE; pdir_index++) {
             // get pdir
             union x86_64_pdir_entry *pdir = (union x86_64_pdir_entry *)pdpt_lv + pdir_index;
+            pt = (union x86_64_ptable_entry*)pdir;
             if (!pdir->raw) { continue; }
+            // check if pdir or huge page
+            if (pt->huge.always1) {
+                // is huge page mapping
+                genpaddr_t paddr = (genpaddr_t)pt->huge.base_addr << HUGE_PAGE_BITS;
+                printf("%d.%d: 0x%"PRIxGENPADDR"\n", pdpt_index, pdir_index, paddr);
+                // goto next pdpt entry
+                continue;
+            }
             genpaddr_t pdir_gp = pdir->d.base_addr << BASE_PAGE_BITS;
             lvaddr_t pdir_lv = local_phys_to_mem(gen_phys_to_local_phys(pdir_gp));
 
             for (int ptable_index = 0; ptable_index < X86_64_PTABLE_SIZE; ptable_index++) {
                 // get ptable
-                union x86_64_ptable_entry *ptable = (union x86_64_ptable_entry *)pdir_lv + ptable_index;
+                union x86_64_pdir_entry *ptable = (union x86_64_pdir_entry *)pdir_lv + ptable_index;
+                pt = (union x86_64_ptable_entry *)ptable;
                 if (!ptable->raw) { continue; }
-                genpaddr_t ptable_gp = ptable->base.base_addr << BASE_PAGE_BITS;
+                // check if ptable or large page
+                if (pt->large.always1) {
+                    // is large page mapping
+                    genpaddr_t paddr = (genpaddr_t)pt->large.base_addr << LARGE_PAGE_BITS;
+                    printf("%d.%d.%d: 0x%"PRIxGENPADDR"\n", pdpt_index, pdir_index, ptable_index, paddr);
+                    // goto next pdir entry
+                    continue;
+                }
+                genpaddr_t ptable_gp = ptable->d.base_addr << BASE_PAGE_BITS;
                 lvaddr_t ptable_lv = local_phys_to_mem(gen_phys_to_local_phys(ptable_gp));
 
                 for (int entry = 0; entry < X86_64_PTABLE_SIZE; entry++) {
index 93575e2..caf03ac 100644 (file)
@@ -4,12 +4,12 @@
  */
 
 /*
- * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
+ * Copyright (c) 2007-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.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
  */
 
 #ifndef KERNEL_TARGET_X86_64_PAGING_H
@@ -108,6 +108,24 @@ union x86_64_ptable_entry {
         uint64_t        global          :1;
         uint64_t        available       :3;
         uint64_t        attr_index      :1;
+        uint64_t        reserved        :17;
+        uint64_t        base_addr       :10;
+        uint64_t        reserved2       :12;
+        uint64_t        available2      :11;
+        uint64_t        execute_disable :1;
+    } huge;
+    struct {
+        uint64_t        present         :1;
+        uint64_t        read_write      :1;
+        uint64_t        user_supervisor :1;
+        uint64_t        write_through   :1;
+        uint64_t        cache_disabled  :1;
+        uint64_t        accessed        :1;
+        uint64_t        dirty           :1;
+        uint64_t        always1         :1;
+        uint64_t        global          :1;
+        uint64_t        available       :3;
+        uint64_t        attr_index      :1;
         uint64_t        reserved        :8;
         uint64_t        base_addr       :X86_64_PAGING_LARGE_BASE_BITS;
         uint64_t        reserved2       :X86_64_PAGING_RESERVED_BITS;
@@ -188,6 +206,36 @@ static inline void paging_x86_64_map_table(union x86_64_pdir_entry *entry,
 }
 
 /**
+ * \brief Maps a huge page.
+ *
+ * From huge page table entry, pointed to by 'entry', maps physical address
+ * 'base' with page attribute bitmap 'bitmap'.
+ *
+ * \param entry         Pointer to page table entry to map from.
+ * \param base          Physical address to map to (will be page-aligned).
+ * \param bitmap        Bitmap to apply to page attributes.
+ */
+static inline void paging_x86_64_map_huge(union x86_64_ptable_entry *entry,
+                                           lpaddr_t base, uint64_t bitmap)
+{
+    union x86_64_ptable_entry tmp;
+    tmp.raw = X86_64_PTABLE_CLEAR;
+
+    tmp.huge.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0;
+    tmp.huge.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0;
+    tmp.huge.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0;
+    tmp.huge.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0;
+    tmp.huge.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0;
+    tmp.huge.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0;
+    tmp.huge.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0;
+    tmp.huge.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
+    tmp.huge.always1 = 1;
+    tmp.huge.base_addr = base >> X86_64_HUGE_PAGE_BITS;
+    
+    *entry = tmp;
+}
+
+/**
  * \brief Maps a large page.
  *
  * From large page table entry, pointed to by 'entry', maps physical address
@@ -218,7 +266,7 @@ static inline void paging_x86_64_map_large(union x86_64_ptable_entry *entry,
     tmp.large.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
     tmp.large.always1 = 1;
     tmp.large.base_addr = base >> 21;
-
+    
     *entry = tmp;
 }
 
index 79229f1..3014dac 100644 (file)
@@ -4,12 +4,13 @@
  */
 
 /*
- * Copyright (c) 2012 ETH Zurich.
+ * Copyright (c) 2012, 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 <paging_generic.h>
@@ -225,6 +226,7 @@ errval_t lookup_cap_for_mapping(genpaddr_t paddr, lvaddr_t pte, struct cte **ret
     return SYS_ERR_CAP_NOT_FOUND;
 }
 
+// TODO: cleanup arch compatibility mess for page size selection
 errval_t paging_tlb_flush_range(struct cte *frame, size_t pages)
 {
     // reconstruct first virtual address for TLB flushing
@@ -250,9 +252,36 @@ errval_t paging_tlb_flush_range(struct cte *frame, size_t pages)
             PRIxGENVADDR"--0x%"PRIxGENVADDR"\n",
             vaddr, vaddr+(pages * BASE_PAGE_SIZE));
     // flush TLB entries for all modified pages
+    size_t page_size = 0;
+    switch(leaf_pt->cap.type) {
+#if __x86_64__
+        case ObjType_VNode_x86_64_ptable:
+            page_size = X86_64_BASE_PAGE_SIZE;
+            break;
+        case ObjType_VNode_x86_64_pdir:
+            page_size = X86_64_LARGE_PAGE_SIZE;
+            break;
+        case ObjType_VNode_x86_64_pdpt:
+            page_size = X86_64_HUGE_PAGE_SIZE;
+            break;
+#elif __i386__
+        case ObjType_VNode_x86_32_ptable:
+            page_size = X86_32_BASE_PAGE_SIZE;
+            break;
+        case ObjType_VNode_x86_32_pdir:
+            page_size = X86_32_LARGE_PAGE_SIZE;
+            break;
+#else
+#error setup page sizes for arch
+#endif
+        default:
+            break;
+    }
+    assert(page_size);
+    // TODO: check what tlb flushing instructions expect for large/huge pages
     for (int i = 0; i < pages; i++) {
         do_one_tlb_flush(vaddr);
-        vaddr += BASE_PAGE_SIZE;
+        vaddr += page_size;
     }
 
     return SYS_ERR_OK;
index 4a3256e..9d733a0 100644 (file)
@@ -1,5 +1,6 @@
 --------------------------------------------------------------------------
 -- Copyright (c) 2007-2012, ETH Zurich
+-- Copyright (c) 2014, HP Labs.
 -- All rights reserved.
 --
 -- This file is distributed under the terms in the attached LICENSE file.
             getsrcs "multihop" = [ "multihop_chan.c" ]
             getsrcs _ = []
 
+      -- configure default morecore pagesize based on Config.hs
+      morecore_pagesize "x86_64" = case Config.morecore_pagesize of
+          "large" -> "LARGE_PAGE_SIZE"
+          "huge"  -> "HUGE_PAGE_SIZE"
+          _       -> "BASE_PAGE_SIZE"
+      morecore_pagesize "x86_32" = case Config.morecore_pagesize of
+          "large" -> "LARGE_PAGE_SIZE"
+          _       -> "BASE_PAGE_SIZE"
+      morecore_pagesize _ = "BASE_PAGE_SIZE"
+
+
       -- sources specific to the architecture family
       archfam_srcs "x86_32"  = [ "arch/x86_32/debug.c" ,
                               "arch/x86_32/dispatch.c" , "arch/x86_32/syscalls.c" ,
                                               ("octopus", ["rpcclient"]),
                                               ("spawn", ["rpcclient"]),
                                               ("arrakis", ["rpcclient"])],
+                    addCFlags = [ "-DMORECORE_PAGESIZE="++(morecore_pagesize arch) ],
                     addIncludes = [ "include", "include" ./. arch_dir ],
                     addGeneratedDependencies = [ "/include/asmoffsets.h" ]
                   }
             getsrcs "multihop" = [ "multihop_chan.c" ]
             getsrcs _ = []
 
+      -- configure default morecore pagesize based on Config.hs
+      morecore_pagesize "x86_64" = case Config.morecore_pagesize of
+          "large" -> "LARGE_PAGE_SIZE"
+          "huge"  -> "HUGE_PAGE_SIZE"
+          _       -> "BASE_PAGE_SIZE"
+      morecore_pagesize "x86_32" = case Config.morecore_pagesize of
+          "large" -> "LARGE_PAGE_SIZE"
+          _       -> "BASE_PAGE_SIZE"
+      morecore_pagesize _ = "BASE_PAGE_SIZE"
+
+
       -- sources specific to the architecture family
       archfam_srcs "x86_32"  = [ "arch/x86_32/debug.c" ,
                               "arch/x86_32/dispatch.c" , "arch/x86_32/syscalls.c" ,
                     cFiles = arch_srcs arch ++ archfam_srcs (archFamily arch)
                              ++ common_srcs ++ idc_srcs,
                     assemblyFiles = arch_assembly (archFamily arch),
-                    addCFlags = [ "-DARRAKIS" ],
+                    addCFlags = [ "-DARRAKIS", "-DMORECORE_PAGESIZE="++(morecore_pagesize arch) ],
                     flounderBindings = [ "mem", "octopus", "interdisp", "spawn", "arrakis",
                                          "terminal" ],
                     -- only makes sense to compile monitor binding for lmp
index 330223a..27bdde6 100644 (file)
@@ -4,12 +4,12 @@
  */
 
 /*
- * Copyright (c) 2010, ETH Zurich.
+ * Copyright (c) 2010-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.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
  */
 
 /*
 #define ARM_USER_L1_OFFSET(addr) ((uintptr_t)(addr >> 22) & 0x3ffu)
 #define ARM_USER_L2_OFFSET(addr) ((uintptr_t)(addr >> 12) & 0x3ffu)
 
+//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)
 {
@@ -281,13 +286,25 @@ 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 = get_ptable(pmap, vaddr, &ptable);
+    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
@@ -303,6 +320,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
@@ -319,12 +337,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;
+    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, BASE_PAGE_SIZE);
-    size_t pte_count = DIVIDE_ROUND_UP(size, BASE_PAGE_SIZE);
+    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)) {
@@ -333,8 +367,8 @@ 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);
-        genvaddr_t temp_end = vaddr + c * BASE_PAGE_SIZE;
+        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)) {
             return err_push(err, LIB_ERR_PMAP_DO_MAP);
@@ -343,8 +377,8 @@ static errval_t do_map(struct pmap_arm *pmap, genvaddr_t vaddr,
         // map full leaves
         while (ARM_L1_OFFSET(temp_end) < ARM_L1_OFFSET(vend)) { // update vars
             vaddr = temp_end;
-            temp_end = vaddr + ARM_L2_MAX_ENTRIES * BASE_PAGE_SIZE;
-            offset += c * BASE_PAGE_SIZE;
+            temp_end = vaddr + ARM_L2_MAX_ENTRIES * page_size;
+            offset += c * page_size;
             c = ARM_L2_MAX_ENTRIES;
             // copy cap
             struct capref next;
@@ -366,7 +400,7 @@ static errval_t do_map(struct pmap_arm *pmap, genvaddr_t vaddr,
         }
 
         // map remaining part
-        offset += c * BASE_PAGE_SIZE;
+        offset += c * page_size;
         c = ARM_L2_OFFSET(vend) - ARM_L2_OFFSET(temp_end);
         if (c) {
             // copy cap
@@ -425,6 +459,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
@@ -516,13 +557,31 @@ map(struct pmap     *pmap,
 {
     struct pmap_arm *pmap_arm = (struct pmap_arm *)pmap;
 
-    size   += BASE_PAGE_OFFSET(offset);
-    size    = ROUND_UP(size, BASE_PAGE_SIZE);
-    offset -= BASE_PAGE_OFFSET(offset);
+    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
+        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) {
@@ -680,6 +739,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)
 {
@@ -813,6 +931,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 d452874..e5a4daa 100644 (file)
@@ -5,6 +5,7 @@
 
 /*
  * Copyright (c) 2011, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
@@ -22,4 +23,45 @@ errval_t pmap_x86_deserialise(struct pmap *pmap, void *buf, size_t buflen);
 errval_t pmap_x86_determine_addr(struct pmap *pmap, struct memobj *memobj,
                                  size_t alignment, genvaddr_t *vaddr);
 
+/**
+ * \brief check whether vnode `root` has children in [entry .. entry+len).
+ * \return * true iff `root` has children in [entry .. entry+len) and
+ *           only_pages false
+ *         * true iff `root` has valid page mappings in [entry .. entry+len)
+ *           and only_pages true
+ */
+bool has_vnode(struct vnode *root, uint32_t entry, size_t len,
+               bool only_pages);
+/**
+ * \return vnode at `entry` in `root`. NULL if no vnode there.
+ */
+struct vnode *find_vnode(struct vnode *root, uint16_t entry);
+
+/**
+ * \return true iff [entry..entry+npages) inside a child of `root`.
+ */
+bool inside_region(struct vnode *root, uint32_t entry, uint32_t npages);
+
+/**
+ * \brief remove vnode `item` from list of children of `root`.
+ */
+void remove_vnode(struct vnode *root, struct vnode *item);
+
+/**
+ * \brief allocate vnode as child of `root` with type `type`. Allocates the
+ * struct vnode with `pmap`'s slab allocator.
+ * \arg entry the entry at which the new vnode is inserted
+ * \arg retvnode pointer to the new vnode.
+ */
+errval_t alloc_vnode(struct pmap_x86 *pmap, struct vnode *root,
+                     enum objtype type, uint32_t entry,
+                     struct vnode **retvnode);
+
+/**
+ * \brief remove vnodes with no leafs in [entry .. entry+len), destroy their
+ * associated capabilities and free their slabs.
+ */
+void remove_empty_vnodes(struct pmap_x86 *pmap, struct vnode *root,
+                         uint32_t entry, size_t len);
+
 #endif // TARGET_X86_BARRELFISH_PMAP_X86_H
index 6e18d67..9c134d2 100644 (file)
@@ -4,7 +4,8 @@
  */
 
 /*
- * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, ETH Zurich.
+ * Copyright (c) 2007-2012, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
@@ -148,6 +149,45 @@ errval_t trace_my_setup(void)
 
 static bool request_done = false;
 
+static bool parse_argv(struct spawn_domain_params *params, size_t *morecore_alignment)
+{
+    // grab pagesize config from argv if available
+    size_t morecore_pagesize = MORECORE_PAGESIZE;
+    int i = 1;
+    bool found = false;
+    for (; i < params->argc; i++) {
+        if (!found) {
+            if (!strncmp(params->argv[i], "morecore=", 9)) {
+                morecore_pagesize = strtol(params->argv[i]+9, NULL, 0);
+                // check for valid page size
+                switch (morecore_pagesize) {
+#ifdef __x86_64__
+                    case HUGE_PAGE_SIZE:
+#endif
+                    case BASE_PAGE_SIZE:
+                    case LARGE_PAGE_SIZE:
+                        break;
+                    default:
+                        morecore_pagesize = MORECORE_PAGESIZE;
+                }
+                found = true;
+            }
+        } else {
+            // found so move all other args one to the front
+            params->argv[i-1] = params->argv[i];
+        }
+    }
+    if (found) {
+        params->argc -= 1;
+    }
+
+    if (morecore_alignment) {
+        *morecore_alignment = morecore_pagesize;
+    }
+
+    return found;
+}
+
 /** \brief Initialise libbarrelfish.
  *
  * This runs on a thread in every domain, after the dispatcher is setup but
@@ -197,7 +237,16 @@ errval_t barrelfish_init_onthread(struct spawn_domain_params *params)
         // TODO: the kernel boots us with a deterministic pmap structure: use it
     }
 
-    err = morecore_init();
+    if (init_domain) {
+        // we cannot use large pages in the init domains because we are not
+        // connected to the memory server and need to work with the 4k pages
+        // in the base cn.
+        err = morecore_init(BASE_PAGE_SIZE);
+    } else {
+        size_t morecore_pagesize = 0;
+        parse_argv(params, &morecore_pagesize);
+        err = morecore_init(morecore_pagesize);
+    }
     if (err_is_fail(err)) {
         return err_push(err, LIB_ERR_MORECORE_INIT);
     }
@@ -250,6 +299,12 @@ errval_t barrelfish_init_onthread(struct spawn_domain_params *params)
         return err_push(err, LIB_ERR_RAM_ALLOC_SET);
     }
 
+    // switch morecore to intended configuration
+    err = morecore_reinit();
+    if (err_is_fail(err)) {
+        return err_push(err, LIB_ERR_MORECORE_INIT);
+    }
+
 #ifdef CONFIG_TRACE
     err = trace_my_setup();
     if (err_is_fail(err)) {
index eb9c9ef..dfb5bcd 100644 (file)
@@ -5,11 +5,12 @@
 
 /*
  * Copyright (c) 2007, 2008, 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>
@@ -107,14 +108,22 @@ Header *get_malloc_freep(void)
     return get_morecore_state()->header_freep;
 }
 
-errval_t morecore_init(void)
+errval_t morecore_init(size_t alignment)
 {
     errval_t err;
     struct morecore_state *state = get_morecore_state();
 
     thread_mutex_init(&state->mutex);
 
-    err = vspace_mmu_aware_init(&state->mmu_state, HEAP_REGION);
+    // setup flags that match the alignment
+    vregion_flags_t morecore_flags = VREGION_FLAGS_READ_WRITE;
+#if __x86_64__
+    morecore_flags |= (alignment == HUGE_PAGE_SIZE ? VREGION_FLAGS_HUGE : 0);
+#endif
+    morecore_flags |= (alignment == LARGE_PAGE_SIZE ? VREGION_FLAGS_LARGE : 0);
+
+    err = vspace_mmu_aware_init_aligned(&state->mmu_state, HEAP_REGION,
+            alignment, morecore_flags);
     if (err_is_fail(err)) {
         return err_push(err, LIB_ERR_VSPACE_MMU_AWARE_INIT);
     }
@@ -124,3 +133,24 @@ errval_t morecore_init(void)
 
     return SYS_ERR_OK;
 }
+
+errval_t morecore_reinit(void)
+{
+    errval_t err;
+    struct morecore_state *state = get_morecore_state();
+
+    size_t mapoffset = state->mmu_state.mapoffset;
+    size_t remapsize = ROUND_UP(mapoffset, state->mmu_state.alignment);
+    if (remapsize <= mapoffset) {
+        // don't need to do anything if we only recreate the exact same
+        // mapping
+        return SYS_ERR_OK;
+    }
+    struct capref frame;
+    size_t retsize;
+    err = frame_alloc(&frame, remapsize, &retsize);
+    if (err_is_fail(err)) {
+        return err;
+    }
+    return vspace_mmu_aware_reset(&state->mmu_state, frame, remapsize);
+}
index 0f21419..cb91e6e 100644 (file)
 
 /*
  * Copyright (c) 2010, 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>
@@ -77,6 +78,7 @@ errval_t multi_alloc(struct slot_allocator *ca, struct capref *ret)
         err = mca->top->alloc(mca->top, &cap);
         if (err_is_fail(err)) {
             thread_mutex_unlock(&ca->mutex);
+            debug_printf("top allocator out of slots; can't refill\n");
             return err_push(err, LIB_ERR_SLOT_ALLOC);
         }
         thread_mutex_unlock(&ca->mutex); // cnode_create_raw uses ram_alloc
index 0f7c114..e9c18e1 100644 (file)
@@ -5,6 +5,7 @@
 
 /*
  * Copyright (c) 2011, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
 #include <barrelfish/pmap.h>
 #include "target/x86/pmap_x86.h"
 
+// this should work for x86_64 and x86_32.
+bool has_vnode(struct vnode *root, uint32_t entry, size_t len,
+               bool only_pages)
+{
+    assert(root != NULL);
+    assert(root->is_vnode);
+    struct vnode *n;
+
+    uint32_t end_entry = entry + len;
+
+    // region we check [entry .. end_entry)
+
+    for (n = root->u.vnode.children; n; n = n->next) {
+        // n is page table, we need to check if it's anywhere inside the
+        // region to check [entry .. end_entry)
+        // this amounts to n->entry == entry for len = 1
+        if (n->is_vnode && n->entry >= entry && n->entry < end_entry) {
+            if (only_pages) {
+                return has_vnode(n, 0, PTABLE_SIZE, true);
+            }
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+            debug_printf("1: found page table inside our region\n");
+#endif
+            return true;
+        } else if (n->is_vnode) {
+            // all other vnodes do not overlap with us, so go to next
+            assert(n->entry < entry || n->entry >= end_entry);
+            continue;
+        }
+        // this remains the same regardless of `only_pages`.
+        // n is frame [n->entry .. end)
+        // 3 cases:
+        // 1) entry < n->entry && end_entry >= end --> n is a strict subset of
+        // our region
+        // 2) entry inside n (entry >= n->entry && entry < end)
+        // 3) end_entry inside n (end_entry >= n->entry && end_entry < end)
+        uint32_t end = n->entry + n->u.frame.pte_count;
+        if (entry < n->entry && end_entry >= end) {
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+            debug_printf("2: found a strict subset of our region: (%"
+                    PRIu32"--%"PRIu32") < (%"PRIu32"--%"PRIu32")\n",
+                    n->entry, end, entry, end_entry);
+#endif
+            return true;
+        }
+        if (entry >= n->entry && entry < end) {
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+            debug_printf("3: found a region starting inside our region: (%"
+                    PRIu32"--%"PRIu32") <> (%"PRIu32"--%"PRIu32")\n",
+                    n->entry, end, entry, end_entry);
+#endif
+            return true;
+        }
+        if (end_entry > n->entry && end_entry < end) {
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+            debug_printf("4: found a region ending inside our region: (%"
+                    PRIu32"--%"PRIu32") <> (%"PRIu32"--%"PRIu32")\n",
+                    n->entry, end, entry, end_entry);
+#endif
+            return true;
+        }
+    }
+
+    return false;
+}
+
+/**
+ * \brief Starting at a given root, return the vnode with entry equal to #entry
+ */
+struct vnode *find_vnode(struct vnode *root, uint16_t entry)
+{
+    assert(root != NULL);
+    assert(root->is_vnode);
+    struct vnode *n;
+
+    for(n = root->u.vnode.children; n != NULL; n = n->next) {
+        if(n->entry == entry) {
+            return n;
+        }
+    }
+    return NULL;
+}
+
+bool inside_region(struct vnode *root, uint32_t entry, uint32_t npages)
+{
+    assert(root != NULL);
+    assert(root->is_vnode);
+
+    struct vnode *n;
+
+    for (n = root->u.vnode.children; n; n = n->next) {
+        if (!n->is_vnode) {
+            uint16_t end = n->entry + n->u.frame.pte_count;
+            if (n->entry <= entry && entry + npages <= end) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+void remove_vnode(struct vnode *root, struct vnode *item)
+{
+    assert(root->is_vnode);
+    struct vnode *walk = root->u.vnode.children;
+    struct vnode *prev = NULL;
+    while (walk) {
+        if (walk == item) {
+            if (prev) {
+                prev->next = walk->next;
+                return;
+            } else {
+                root->u.vnode.children = walk->next;
+                return;
+            }
+        }
+        prev = walk;
+        walk = walk->next;
+    }
+    USER_PANIC("Should not get here");
+}
+
+/**
+ * \brief Allocates a new VNode, adding it to the page table and our metadata
+ */
+errval_t alloc_vnode(struct pmap_x86 *pmap, struct vnode *root,
+                     enum objtype type, uint32_t entry,
+                     struct vnode **retvnode)
+{
+    errval_t err;
+
+    struct vnode *newvnode = slab_alloc(&pmap->slab);
+    if (newvnode == NULL) {
+        return LIB_ERR_SLAB_ALLOC_FAIL;
+    }
+
+    // The VNode capability
+    err = pmap->p.slot_alloc->alloc(pmap->p.slot_alloc, &newvnode->u.vnode.cap);
+    if (err_is_fail(err)) {
+        return err_push(err, LIB_ERR_SLOT_ALLOC);
+    }
+
+    err = vnode_create(newvnode->u.vnode.cap, type);
+    if (err_is_fail(err)) {
+        return err_push(err, LIB_ERR_VNODE_CREATE);
+    }
+
+    // Map it
+    err = vnode_map(root->u.vnode.cap, newvnode->u.vnode.cap, entry,
+                    PTABLE_ACCESS_DEFAULT, 0, 1);
+    if (err_is_fail(err)) {
+        return err_push(err, LIB_ERR_VNODE_MAP);
+    }
+
+    // The VNode meta data
+    newvnode->is_vnode  = true;
+    newvnode->entry     = entry;
+    newvnode->next      = root->u.vnode.children;
+    root->u.vnode.children = newvnode;
+    newvnode->u.vnode.children = NULL;
+
+    *retvnode = newvnode;
+    return SYS_ERR_OK;
+}
+
+void remove_empty_vnodes(struct pmap_x86 *pmap, struct vnode *root,
+                         uint32_t entry, size_t len)
+{
+    errval_t err;
+    uint32_t end_entry = entry + len;
+    for (struct vnode *n = root->u.vnode.children; n; n = n->next) {
+        if (n->entry >= entry && n->entry < end_entry) {
+            // sanity check and skip leaf entries
+            if (!n->is_vnode) {
+                continue;
+            }
+            // here we know that all vnodes we're interested in are
+            // page tables
+            assert(n->is_vnode);
+            if (n->u.vnode.children) {
+                remove_empty_vnodes(pmap, n, 0, PTABLE_SIZE);
+            }
+
+            // unmap
+            err = vnode_unmap(root->u.vnode.cap, n->u.vnode.cap, n->entry, 1);
+            if (err_is_fail(err)) {
+                debug_printf("remove_empty_vnodes: vnode_unmap: %s\n",
+                        err_getstring(err));
+            }
+
+            // delete capability
+            err = cap_destroy(n->u.vnode.cap);
+            if (err_is_fail(err)) {
+                debug_printf("remove_empty_vnodes: cap_destroy: %s\n",
+                        err_getstring(err));
+            }
+
+            // remove vnode from list
+            remove_vnode(root, n);
+            slab_free(&pmap->slab, n);
+        }
+    }
+}
+
+
 /*
  * The serialisation format is depressingly ad-hoc, and assumes a depth-first
  * walk of the tree. Each vnode is encoded as an entry in an array.
index 158ef94..fa7147b 100644 (file)
  */
 
 /*
- * Copyright (c) 2010, 2011, ETH Zurich.
+ * Copyright (c) 2010-2013 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 <stdio.h>
 #include "target/x86/pmap_x86.h"
 
+
 // Location and size of virtual address space reserved for mapping
 // frames backing refill_slabs
 #define META_DATA_RESERVED_BASE ((lvaddr_t)1UL*1024*1024*1024)
 #define META_DATA_RESERVED_SIZE (X86_32_BASE_PAGE_SIZE * 1200)
 
+// flags for large pages
+#define FLAGS_LARGE 0x0100
+
 /**
  * \brief Translate generic vregion flags to architecture specific pmap flags
  */
@@ -67,132 +72,43 @@ static inline bool is_same_pdir(genvaddr_t va1, genvaddr_t va2)
 {
     return (va1>>X86_32_LARGE_PAGE_BITS) == (va2>>X86_32_LARGE_PAGE_BITS);
 }
+static inline bool is_same_pdpt(genvaddr_t va1, genvaddr_t va2)
+{
+#ifdef CONFIG_PAE
+    // PDPT in PAE has 4 entries, uses the topmost two bits
+    return (va1>>30) == (va2>>30);
+#else
+    // since there is no PDPT in 32bit, trivially true
+    return true;
+#endif
+}
 static inline genvaddr_t get_addr_prefix(genvaddr_t va)
 {
     return va >> X86_32_LARGE_PAGE_BITS;
 }
+
 /**
- * \brief Starting at a given root, return the vnode with entry equal to #entry
+ * \brief Returns the vnode for the page directory mapping a given vspace address
  */
-static struct vnode *find_vnode(struct vnode *root, uint16_t entry)
-{
-    assert(root != NULL);
-    assert(root->is_vnode);
-    struct vnode *n;
-
-    for(n = root->u.vnode.children; n != NULL; n = n->next) {
-        if(n->entry == entry) {
-            return n;
-        }
-    }
-    return NULL;
-}
-
-static bool inside_region(struct vnode *root, uint32_t entry, uint32_t npages)
-{
-    assert(root != NULL);
-    assert(root->is_vnode);
-
-    struct vnode *n;
-
-    for (n = root->u.vnode.children; n; n = n->next) {
-        if (!n->is_vnode) {
-            uint16_t end = n->entry + n->u.frame.pte_count;
-            if (n->entry <= entry && entry + npages <= end) {
-                return true;
-            }
-        }
-    }
-
-    return false;
-}
-
-static bool has_vnode(struct vnode *root, uint32_t entry, size_t len)
+static errval_t get_pdir(struct pmap_x86 *pmap, genvaddr_t base,
+                           struct vnode **pdir)
 {
+#ifdef CONFIG_PAE
+    struct vnode *root = &pmap->root;
     assert(root != NULL);
-    assert(root->is_vnode);
-    struct vnode *n;
-
-    uint32_t end_entry = entry + len;
 
-    for (n = root->u.vnode.children; n; n = n->next) {
-        if (n->is_vnode && n->entry == entry) {
-            return true;
-        }
-        // n is frame
-        uint32_t end = n->entry + n->u.frame.pte_count;
-        if (n->entry < entry && end > end_entry) {
-            return true;
-        }
-        if (n->entry >= entry && n->entry < end_entry) {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-static void remove_vnode(struct vnode *root, struct vnode *item)
-{
-    assert(root->is_vnode);
-    struct vnode *walk = root->u.vnode.children;
-    struct vnode *prev = NULL;
-    while (walk) {
-        if (walk == item) {
-            if (prev) {
-                prev->next = walk->next;
-                return;
-            } else {
-                root->u.vnode.children = walk->next;
-                return;
-            }
+    // PDPTE mapping
+    if((*pdir = find_vnode(root, X86_32_PDPTE_BASE(base))) == NULL) {
+        errval_t err = alloc_vnode(pmap, root, ObjType_VNode_x86_32_pdir,
+                          X86_32_PDPTE_BASE(base), pdir);
+        if (err_is_fail(err)) {
+            return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
         }
-        prev = walk;
-        walk = walk->next;
     }
-    USER_PANIC("Should not get here");
-}
-
-/**
- * \brief Allocates a new VNode, adding it to the page table and our metadata
- */
-static errval_t alloc_vnode(struct pmap_x86 *pmap, struct vnode *root,
-                            enum objtype type, uint32_t entry,
-                            struct vnode **retvnode)
-{
-    errval_t err;
-
-    struct vnode *newvnode = slab_alloc(&pmap->slab);
-    if (newvnode == NULL) {
-        return LIB_ERR_SLAB_ALLOC_FAIL;
-    }
-
-    // The VNode capability
-    err = pmap->p.slot_alloc->alloc(pmap->p.slot_alloc, &newvnode->u.vnode.cap);
-    if (err_is_fail(err)) {
-        return err_push(err, LIB_ERR_SLOT_ALLOC);
-    }
-
-    err = vnode_create(newvnode->u.vnode.cap, type);
-    if (err_is_fail(err)) {
-        return err_push(err, LIB_ERR_VNODE_CREATE);
-    }
-
-    // Map it
-    err = vnode_map(root->u.vnode.cap, newvnode->u.vnode.cap, entry,
-                    X86_32_PTABLE_ACCESS_DEFAULT, 0, 1);
-    if (err_is_fail(err)) {
-        return err_push(err, LIB_ERR_VNODE_MAP);
-    }
-
-    // The VNode meta data
-    newvnode->is_vnode  = true;
-    newvnode->entry     = entry;
-    newvnode->next      = root->u.vnode.children;
-    root->u.vnode.children      = newvnode;
-    newvnode->u.vnode.children  = NULL;
+#else
+    *pdir = &pmap->root;
+#endif
 
-    *retvnode = newvnode;
     return SYS_ERR_OK;
 }
 
@@ -204,22 +120,10 @@ static errval_t get_ptable(struct pmap_x86 *pmap, genvaddr_t base,
 {
     errval_t err;
     struct vnode *pdir;
-
-#ifdef CONFIG_PAE
-    struct vnode *root = &pmap->root;
-    assert(root != NULL);
-
-    // PDPTE mapping
-    if((pdir = find_vnode(root, X86_32_PDPTE_BASE(base))) == NULL) {
-        err = alloc_vnode(pmap, root, ObjType_VNode_x86_32_pdir,
-                          X86_32_PDPTE_BASE(base), &pdir);
-        if (err_is_fail(err)) {
-            return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
-        }
+    err = get_pdir(pmap, base, &pdir);
+    if (err_is_fail(err)) {
+        return err;
     }
-#else
-    pdir = &pmap->root;
-#endif
 
     // PDIR mapping
     if((*ptable = find_vnode(pdir, X86_32_PDIR_BASE(base))) == NULL) {
@@ -233,50 +137,78 @@ static errval_t get_ptable(struct pmap_x86 *pmap, genvaddr_t base,
     return SYS_ERR_OK;
 }
 
-static struct vnode *find_ptable(struct pmap_x86 *pmap, genvaddr_t base)
+static struct vnode *find_pdir(struct pmap_x86 *pmap, genvaddr_t base)
 {
     struct vnode *root = &pmap->root;
-    struct vnode *pdir;
     assert(root != NULL);
 
 #ifdef CONFIG_PAE
     // PDPT mapping
-    if((pdir = find_vnode(root, X86_32_PDPT_BASE(base))) == NULL) {
-        return NULL;
-    }
+    return find_vnode(root, X86_32_PDPTE_BASE(base));
 #else
-    pdir = root;
+    return root;
 #endif
+}
 
-    // PDIR mapping
-    return find_vnode(pdir, X86_32_PDIR_BASE(base));
+static struct vnode *find_ptable(struct pmap_x86 *pmap, genvaddr_t base)
+{
+    struct vnode *pdir = find_pdir(pmap, base);
+
+    if (pdir) {
+        // PDIR mapping
+        return find_vnode(pdir, X86_32_PDIR_BASE(base));
+    } else {
+        return NULL;
+    }
 }
 
-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,
+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)
 {
+    //printf("[do_single_map] vaddr = 0x%"PRIxGENVADDR"\n", vaddr);
     // translate flags
     paging_x86_32_flags_t pmap_flags = vregion_to_pmap_flag(flags);
 
-    // Get the page table
+    // Get the page table and do mapping specific alterations
     struct vnode *ptable;
-    errval_t err = get_ptable(pmap, vaddr, &ptable);
+    errval_t err;
+    size_t base;
+
+    if (flags & VREGION_FLAGS_LARGE) {
+        //4M/2M(PAE) mapping
+        err = get_pdir(pmap, vaddr, &ptable);
+        base = X86_32_PDIR_BASE(vaddr);
+    } else {
+        //4k mapping
+        err = get_ptable(pmap, vaddr, &ptable);
+        base = X86_32_PTABLE_BASE(vaddr);
+    }    
     if (err_is_fail(err)) {
         return err_push(err, LIB_ERR_PMAP_GET_PTABLE);
     }
+    assert(ptable->is_vnode);
 
     // check if there is an overlapping mapping
-    if (has_vnode(ptable, X86_32_PTABLE_BASE(vaddr), pte_count)) {
-        printf("page already exists in 0x%"PRIxGENVADDR"--0x%"PRIxGENVADDR"\n", vaddr, vend);
-        return LIB_ERR_PMAP_EXISTING_MAPPING;
+    if (has_vnode(ptable, base, pte_count, false)) {
+        if (has_vnode(ptable, base, pte_count, true)) {
+            printf("page already exists in 0x%"
+                    PRIxGENVADDR"--0x%"PRIxGENVADDR"\n", vaddr, vend);
+            return LIB_ERR_PMAP_EXISTING_MAPPING;
+        } else {
+            // clean out empty page tables. We do this here because we benefit
+            // from having the page tables in place when doing lots of small
+            // mappings
+            remove_empty_vnodes(pmap, ptable, base, pte_count);
+        }
     }
 
     // setup userspace mapping
     struct vnode *page = slab_alloc(&pmap->slab);
     assert(page);
     page->is_vnode = false;
-    page->entry = X86_32_PTABLE_BASE(vaddr);
+    page->entry = base;
     page->next  = ptable->u.vnode.children;
     ptable->u.vnode.children = page;
     page->u.frame.cap = frame;
@@ -285,9 +217,10 @@ static errval_t do_single_map(struct pmap_x86 *pmap, genvaddr_t vaddr, genvaddr_
     page->u.frame.pte_count = pte_count;
 
     // do map
-    err = vnode_map(ptable->u.vnode.cap, frame, X86_32_PTABLE_BASE(vaddr),
+    err = vnode_map(ptable->u.vnode.cap, frame, base,
                     pmap_flags, offset, pte_count);
     if (err_is_fail(err)) {
+        printf("error in do_single_map: vnode_map failed\n");
         return err_push(err, LIB_ERR_VNODE_MAP);
     }
 
@@ -301,11 +234,23 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
     //printf("[do_map] vaddr = 0x%"PRIxGENVADDR", size = %zd\n", vaddr, size);
     errval_t err;
 
-    size = ROUND_UP(size, X86_32_BASE_PAGE_SIZE);
-    size_t pte_count = DIVIDE_ROUND_UP(size, X86_32_BASE_PAGE_SIZE);
+    // figure out mapping parameters
+    size_t page_size = X86_32_BASE_PAGE_SIZE;
+    size_t base = X86_32_PTABLE_BASE(vaddr);
+    if(flags & VREGION_FLAGS_LARGE) {
+        //4M/2M (PAE) pages
+        page_size = X86_32_LARGE_PAGE_SIZE;
+        base = X86_32_PDIR_BASE(vaddr);
+    }
+
+    // TODO: needs overhaul for mixed-size mappings
+    // TODO: need to make sure we can map that much
+    size = ROUND_UP(size, page_size);
+    size_t pte_count = DIVIDE_ROUND_UP(size, page_size);
     genvaddr_t vend = vaddr + size;
 
-    if (is_same_pdir(vaddr, vend)) {
+    if (is_same_pdir(vaddr, vend) ||
+        (flags & VREGION_FLAGS_LARGE && is_same_pdpt(vaddr, vend))) {
         // fast path
         err = do_single_map(pmap, vaddr, vend, frame, offset, pte_count, flags);
         if (err_is_fail(err)) {
@@ -314,8 +259,8 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
     }
     else { // multiple leaf page tables
         // first leaf
-        uint32_t c = X86_32_PTABLE_SIZE - X86_32_PTABLE_BASE(vaddr);
-        genvaddr_t temp_end = vaddr + c * X86_32_BASE_PAGE_SIZE;
+        uint32_t c = X86_32_PTABLE_SIZE - base;
+        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)) {
             return err_push(err, LIB_ERR_PMAP_DO_MAP);
@@ -325,8 +270,8 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
         while (get_addr_prefix(temp_end) < get_addr_prefix(vend)) {
             // update vars
             vaddr = temp_end;
-            temp_end = vaddr + X86_32_PTABLE_SIZE * X86_32_BASE_PAGE_SIZE;
-            offset += c * X86_32_BASE_PAGE_SIZE;
+            temp_end = vaddr + X86_32_PTABLE_SIZE * page_size;
+            offset += c * page_size;
             c = X86_32_PTABLE_SIZE;
             // copy cap
             struct capref next;
@@ -341,15 +286,22 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
             frame = next;
 
             // do mapping
-            err = do_single_map(pmap, vaddr, temp_end, frame, offset, X86_32_PTABLE_SIZE, flags);
+            err = do_single_map(pmap, vaddr, temp_end, frame, offset,
+                    X86_32_PTABLE_SIZE, flags);
             if (err_is_fail(err)) {
                 return err_push(err, LIB_ERR_PMAP_DO_MAP);
             }
         }
 
         // map remaining part
-        offset += c * X86_32_BASE_PAGE_SIZE;
-        c = X86_32_PTABLE_BASE(vend) - X86_32_PTABLE_BASE(temp_end);
+        offset += c * page_size;
+        if(flags & VREGION_FLAGS_LARGE) {
+            // 4M/2M (PAE) mapping
+            c = X86_32_PDIR_BASE(vend) - X86_32_PDIR_BASE(temp_end);
+        } else {
+            // 4K mapping
+            c = X86_32_PTABLE_BASE(vend) - X86_32_PTABLE_BASE(temp_end);
+        }
         if (c) {
             // copy cap
             struct capref next;
@@ -379,7 +331,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);
@@ -392,6 +344,17 @@ static size_t max_slabs_for_mapping(size_t bytes)
 #endif
     return max_pages + max_ptable + max_pdir + max_pdpt;
 }
+static size_t max_slabs_for_mapping_large(size_t bytes)
+{
+    size_t max_pages  = DIVIDE_ROUND_UP(bytes, X86_32_LARGE_PAGE_SIZE);
+    size_t max_pdir   = DIVIDE_ROUND_UP(max_pages, X86_32_PTABLE_SIZE) + 1;
+#ifdef CONFIG_PAE
+    size_t max_pdpt   = DIVIDE_ROUND_UP(max_pdir, X86_32_PTABLE_SIZE) + 1;
+#else
+    size_t max_pdpt   = 0;
+#endif
+    return max_pages + max_pdir + max_pdpt;
+}
 
 /**
  * \brief Refill slabs used for metadata
@@ -478,17 +441,29 @@ static errval_t map(struct pmap *pmap, genvaddr_t vaddr, struct capref frame,
                     size_t offset, size_t size, vregion_flags_t flags,
                     size_t *retoff, size_t *retsize)
 {
+    //printf("[map] vaddr = 0x%"PRIxGENVADDR", size = %zd\n", vaddr, size);
     errval_t err;
     struct pmap_x86 *x86 = (struct pmap_x86*)pmap;
+    
+    size_t max_slabs;
 
     // Adjust the parameters to page boundaries
-    size   += X86_32_BASE_PAGE_OFFSET(offset);
-    size    = ROUND_UP(size, X86_32_BASE_PAGE_SIZE);
-    offset -= X86_32_BASE_PAGE_OFFSET(offset);
+    if(flags&FLAGS_LARGE) {
+        // 4M pages/2M pages(PAE)
+        size   += X86_32_LARGE_PAGE_OFFSET(offset);
+        size    = ROUND_UP(size, X86_32_LARGE_PAGE_SIZE);
+        offset -= X86_32_LARGE_PAGE_OFFSET(offset);
+        max_slabs = max_slabs_for_mapping_large(size);
+    } else {
+        // 4K pages
+        size   += X86_32_BASE_PAGE_OFFSET(offset);
+        size    = ROUND_UP(size, X86_32_BASE_PAGE_SIZE);
+        offset -= X86_32_BASE_PAGE_OFFSET(offset);
+        max_slabs = max_slabs_for_mapping(size);
+    }
 
     // Refill slab allocator if necessary
     size_t slabs_free = slab_freecount(&x86->slab);
-    size_t max_slabs = max_slabs_for_mapping(size);
     max_slabs += 4; // minimum amount required to map a page
     if (slabs_free < max_slabs) {
         struct pmap *mypmap = get_current_pmap();
@@ -508,20 +483,62 @@ 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);
     return err;
 }
 
-static errval_t do_single_unmap(struct pmap_x86 *pmap, genvaddr_t vaddr, size_t pte_count, bool delete_cap)
+/**
+ * \brief Find mapping for `vaddr` in `pmap`.
+ * \arg pmap the pmap to search in
+ * \arg vaddr the virtual address to search for
+ * \arg pt the last-level page table meta-data we found if any
+ * \arg page the page meta-data we found if any
+ * \returns `true` iff we found a mapping for vaddr
+ */
+static bool find_mapping(struct pmap_x86 *pmap, genvaddr_t vaddr,
+                         struct vnode **outpt, struct vnode **outpage)
+{
+    struct vnode *pdir = NULL, *pt = NULL, *page = NULL;
+
+    // find page and last-level page table (can be pdir or pdpt)
+    if ((pdir = find_pdir(pmap, vaddr)) != NULL) {
+        page = find_vnode(pdir, X86_32_PDIR_BASE(vaddr));
+        if (page && page->is_vnode) { // not 2M/4M pages
+            pt = page;
+            page = find_vnode(pt, X86_32_PTABLE_BASE(vaddr));
+        } else if (page) {
+            pt = pdir;
+        }
+    }
+    if (outpt) {
+        *outpt = pt;
+    }
+    if (outpage) {
+        *outpage = page;
+    }
+    if (pt) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+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);
+    struct vnode *pt = NULL, *page = NULL;
+
+    find_mapping(pmap, vaddr, &pt, &page);
+
     if (pt) {
-        struct vnode *page = find_vnode(pt, X86_32_PTABLE_BASE(vaddr));
         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);
+            err = vnode_unmap(pt->u.vnode.cap, page->u.frame.cap, page->entry,
+                              page->u.frame.pte_count);
             if (err_is_fail(err)) {
-                printf("vnode_unmap returned error: %s (%d)\n", err_getstring(err), err_no(err));
+                printf("vnode_unmap returned error: %s (%d)\n",
+                        err_getstring(err), err_no(err));
                 return err_push(err, LIB_ERR_VNODE_UNMAP);
             }
 
@@ -536,6 +553,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;
         }
     }
@@ -543,6 +561,15 @@ static errval_t do_single_unmap(struct pmap_x86 *pmap, genvaddr_t vaddr, size_t
     return SYS_ERR_OK;
 }
 
+static inline bool is_large_page(struct vnode *p)
+{
+    return !p->is_vnode && p->u.frame.flags & VREGION_FLAGS_LARGE;
+}
+static inline bool is_huge_page(struct vnode *p)
+{
+    return !p->is_vnode && p->u.frame.flags & VREGION_FLAGS_HUGE;
+}
+
 /**
  * \brief Remove page mappings
  *
@@ -557,12 +584,29 @@ 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;
+
+    if (!find_mapping(x86, vaddr, NULL, &page)) {
+        // TODO: better error
+        return LIB_ERR_PMAP_UNMAP;
+    }
+    assert(!page->is_vnode);
+
+    size_t page_size = X86_32_BASE_PAGE_SIZE;
+    if (is_large_page(page)) {
+        //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) && is_large_page(page))) {
         // 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);
         }
@@ -576,14 +620,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
@@ -648,6 +692,8 @@ static errval_t do_single_modify_flags(struct pmap_x86 *pmap, genvaddr_t vaddr,
  * \param vaddr    The virtual address to unmap
  * \param flags    New flags for the mapping
  * \param retsize  If non-NULL, filled in with the actual size modified
+ *
+ * TODO: fix for large page mappings
  */
 static errval_t modify_flags(struct pmap *pmap, genvaddr_t vaddr, size_t size,
                              vregion_flags_t flags, size_t *retsize)
@@ -772,8 +818,67 @@ 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)
+{
+    struct pmap_x86 *x86 = (struct pmap_x86 *)pmap;
+
+    struct vnode *walk_pdir = x86->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
+    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;
+    // XXX: breaks for PAE
+    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 struct pmap_funcs pmap_funcs = {
     .determine_addr = pmap_x86_determine_addr,
+    .determine_addr_raw = determine_addr_raw,
     .map = map,
     .unmap = unmap,
     .modify_flags = modify_flags,
index 265997f..0303b95 100644 (file)
  */
 
 /*
- * Copyright (c) 2009, 2010, 2011, ETH Zurich.
+ * Copyright (c) 2009-2013 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>
@@ -60,168 +61,93 @@ static paging_x86_64_flags_t vregion_to_pmap_flag(vregion_flags_t vregion_flags)
     return pmap_flags;
 }
 
+// returns whether va1 and va2 share a page directory entry
+// not using X86_64_PDIR_BASE() macro as this would give false positives (same
+// entry in different directories)
 static inline bool is_same_pdir(genvaddr_t va1, genvaddr_t va2)
 {
-    return (va1>>X86_64_LARGE_PAGE_BITS) == (va2>>X86_64_LARGE_PAGE_BITS);
+    return (va1>>X86_64_LARGE_PAGE_BITS) == ((va2-1)>>X86_64_LARGE_PAGE_BITS);
 }
-static inline genvaddr_t get_addr_prefix(genvaddr_t va)
+// returns whether va1 and va2 share a page directory pointer table entry
+static inline bool is_same_pdpt(genvaddr_t va1, genvaddr_t va2)
 {
-    return va >> X86_64_LARGE_PAGE_BITS;
+    return (va1>>X86_64_HUGE_PAGE_BITS) == ((va2-1)>>X86_64_HUGE_PAGE_BITS);
 }
-static bool has_vnode(struct vnode *root, uint32_t entry, size_t len)
+// returns whether va1 and va2 share a page map level 4 entry
+static inline bool is_same_pml4(genvaddr_t va1, genvaddr_t va2)
 {
-    assert(root != NULL);
-    assert(root->is_vnode);
-    struct vnode *n;
-
-    uint32_t end_entry = entry + len;
-
-    for (n = root->u.vnode.children; n; n = n->next) {
-        if (n->is_vnode && n->entry == entry) {
-            return true;
-        }
-        // n is frame
-        uint32_t end = n->entry + n->u.frame.pte_count;
-        if (n->entry < entry && end > end_entry) {
-            return true;
-        }
-        if (n->entry >= entry && n->entry < end_entry) {
-            return true;
-        }
-    }
-
-    return false;
+    // the base macros work here as we only have one pml4.
+    return X86_64_PML4_BASE(va1) == X86_64_PML4_BASE(va2-1);
 }
-
-/**
- * \brief Starting at a given root, return the vnode with starting entry equal to #entry
- */
-static struct vnode *find_vnode(struct vnode *root, uint32_t entry)
+// size indicates how many bits to shift
+static inline genvaddr_t get_addr_prefix(genvaddr_t va, uint8_t size)
 {
-    assert(root != NULL);
-    assert(root->is_vnode);
-    struct vnode *n;
-
-    for(n = root->u.vnode.children; n != NULL; n = n->next) {
-        if(n->entry == entry) {
-            return n;
-        }
-    }
-    return NULL;
+    return va >> size;
 }
 
-static bool inside_region(struct vnode *root, uint32_t entry, uint32_t npages)
+/**
+ * \brief Returns the vnode for the pdpt mapping a given vspace address
+ */
+static inline errval_t get_pdpt(struct pmap_x86 *pmap, genvaddr_t base,
+                                struct vnode **pdpt)
 {
+    errval_t err;
+    struct vnode *root = &pmap->root;
     assert(root != NULL);
-    assert(root->is_vnode);
-
-    struct vnode *n;
 
-    for (n = root->u.vnode.children; n; n = n->next) {
-        if (!n->is_vnode) {
-            uint16_t end = n->entry + n->u.frame.pte_count;
-            if (n->entry <= entry && entry + npages <= end) {
-                return true;
-            }
+    // PML4 mapping
+    if((*pdpt = find_vnode(root, X86_64_PML4_BASE(base))) == NULL) {
+        err = alloc_vnode(pmap, root, ObjType_VNode_x86_64_pdpt,
+                            X86_64_PML4_BASE(base), pdpt);
+        if (err_is_fail(err)) {
+            return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
         }
     }
 
-    return false;
-}
-
-static void remove_vnode(struct vnode *root, struct vnode *item)
-{
-    assert(root->is_vnode);
-    struct vnode *walk = root->u.vnode.children;
-    struct vnode *prev = NULL;
-    while (walk) {
-        if (walk == item) {
-            if (prev) {
-                prev->next = walk->next;
-                return;
-            } else {
-                root->u.vnode.children = walk->next;
-                return;
-            }
-        }
-        prev = walk;
-        walk = walk->next;
-    }
-    assert(!"Should not get here");
+    return SYS_ERR_OK;
 }
 
 /**
- * \brief Allocates a new VNode, adding it to the page table and our metadata
+ * \brief Returns the vnode for the page directory mapping a given vspace
+ * address
  */
-static errval_t alloc_vnode(struct pmap_x86 *pmap, struct vnode *root,
-                            enum objtype type, uint32_t entry,
-                            struct vnode **retvnode)
+static inline errval_t get_pdir(struct pmap_x86 *pmap, genvaddr_t base,
+                                struct vnode **pdir)
 {
     errval_t err;
-
-    struct vnode *newvnode = slab_alloc(&pmap->slab);
-    if (newvnode == NULL) {
-        return LIB_ERR_SLAB_ALLOC_FAIL;
-    }
-
-    // The VNode capability
-    err = pmap->p.slot_alloc->alloc(pmap->p.slot_alloc, &newvnode->u.vnode.cap);
+    struct vnode *pdpt;
+    err = get_pdpt(pmap, base, &pdpt);
     if (err_is_fail(err)) {
-        return err_push(err, LIB_ERR_SLOT_ALLOC);
+        return err;
     }
+    assert(pdpt != NULL);
 
-    err = vnode_create(newvnode->u.vnode.cap, type);
-    if (err_is_fail(err)) {
-        return err_push(err, LIB_ERR_VNODE_CREATE);
-    }
-
-    // Map it
-    //printf("\talloc_vnode calling vnode_map()\n");
-    err = vnode_map(root->u.vnode.cap, newvnode->u.vnode.cap, entry,
-                    PTABLE_ACCESS_DEFAULT, 0, 1);
-    if (err_is_fail(err)) {
-        return err_push(err, LIB_ERR_VNODE_MAP);
+    // PDPT mapping
+    if((*pdir = find_vnode(pdpt, X86_64_PDPT_BASE(base))) == NULL) {
+        err = alloc_vnode(pmap, pdpt, ObjType_VNode_x86_64_pdir,
+                            X86_64_PDPT_BASE(base), pdir);
+        if (err_is_fail(err)) {
+            printf("failure mapping pdpt\n");
+            return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
+        }
     }
 
-    // The VNode meta data
-    newvnode->is_vnode  = true;
-    newvnode->entry     = entry;
-    newvnode->next      = root->u.vnode.children;
-    root->u.vnode.children = newvnode;
-    newvnode->u.vnode.children = NULL;
-
-    *retvnode = newvnode;
     return SYS_ERR_OK;
 }
 
 /**
  * \brief Returns the vnode for the pagetable mapping a given vspace address
  */
-static errval_t get_ptable(struct pmap_x86 *pmap, genvaddr_t base,
-                            struct vnode **ptable)
+static inline errval_t get_ptable(struct pmap_x86 *pmap, genvaddr_t base,
+                                  struct vnode **ptable)
 {
     errval_t err;
-    struct vnode *root = &pmap->root;
-    struct vnode *pdpt, *pdir;
-    assert(root != NULL);
-
-    // PML4 mapping
-    if((pdpt = find_vnode(root, X86_64_PML4_BASE(base))) == NULL) {
-        err = alloc_vnode(pmap, root, ObjType_VNode_x86_64_pdpt,
-                            X86_64_PML4_BASE(base), &pdpt);
-        if (err_is_fail(err)) {
-            return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
-        }
-    }
-
-    // PDPT mapping
-    if((pdir = find_vnode(pdpt, X86_64_PDPT_BASE(base))) == NULL) {
-        err = alloc_vnode(pmap, pdpt, ObjType_VNode_x86_64_pdir,
-                            X86_64_PDPT_BASE(base), &pdir);
-        if (err_is_fail(err)) {
-            return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
-        }
+    struct vnode *pdir;
+    err = get_pdir(pmap, base, &pdir);
+    if (err_is_fail(err)) {
+        return err;
     }
+    assert(pdir != NULL);
 
     // PDIR mapping
     if((*ptable = find_vnode(pdir, X86_64_PDIR_BASE(base))) == NULL) {
@@ -235,56 +161,108 @@ static errval_t get_ptable(struct pmap_x86 *pmap, genvaddr_t base,
     return SYS_ERR_OK;
 }
 
-
 /**
- * \brief Returns the vnode for the pagetable mapping a given vspace address,
- *     without performing allocations as get_ptable() does
+ * \brief Returns the vnode for the page directory pointer table mapping for a
+ * given vspace address
  */
-static struct vnode *find_ptable(struct pmap_x86 *pmap, genvaddr_t base)
+static inline struct vnode *find_pdpt(struct pmap_x86 *pmap, genvaddr_t base)
 {
     struct vnode *root = &pmap->root;
-    struct vnode *pdpt, *pdir;
     assert(root != NULL);
 
-    // PML4 mapping
-    if((pdpt = find_vnode(root, X86_64_PML4_BASE(base))) == NULL) {
+    // PDPT mapping
+    return find_vnode(root, X86_64_PML4_BASE(base));
+}
+
+/**
+ * \brief Returns the vnode for the page directory mapping a given vspace
+ * address, without performing allocations as get_pdir() does
+ */
+static inline struct vnode *find_pdir(struct pmap_x86 *pmap, genvaddr_t base)
+{
+    struct vnode *pdpt = find_pdpt(pmap, base);
+
+    if (pdpt) {
+        // PDPT mapping
+        return find_vnode(pdpt, X86_64_PDPT_BASE(base));
+    } else {
         return NULL;
     }
+}
 
-    // PDPT mapping
-    if((pdir = find_vnode(pdpt, X86_64_PDPT_BASE(base))) == NULL) {
+/**
+ * \brief Returns the vnode for the pagetable mapping a given vspace address,
+ * without performing allocations as get_ptable() does
+ */
+static inline struct vnode *find_ptable(struct pmap_x86 *pmap, genvaddr_t base)
+{
+    struct vnode *pdir = find_pdir(pmap, base);
+
+    if (pdir) {
+        // PDIR mapping
+        return find_vnode(pdir, X86_64_PDIR_BASE(base));
+    } else {
         return NULL;
     }
-
-    // PDIR mapping
-    return find_vnode(pdir, X86_64_PDIR_BASE(base));
 }
 
-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,
+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)
 {
+    if (pte_count == 0) {
+        debug_printf("do_single_map: pte_count == 0, called from %p\n",
+                __builtin_return_address(0));
+        return SYS_ERR_OK;
+    }
+    assert(pte_count > 0);
     // translate flags
     paging_x86_64_flags_t pmap_flags = vregion_to_pmap_flag(flags);
 
-    // Get the page table
+    // Get the paging structure and set paging relevant parameters
     struct vnode *ptable;
-    errval_t err = get_ptable(pmap, vaddr, &ptable);
+    errval_t err;
+    size_t table_base;
+
+    // get the right paging table and address part
+    if(flags & VREGION_FLAGS_LARGE) {
+        //large 2M pages, mapped into pdir
+        err = get_pdir(pmap, vaddr, &ptable);
+        table_base = X86_64_PDIR_BASE(vaddr);
+    } else if (flags & VREGION_FLAGS_HUGE) {
+        //huge 1GB pages, mapped into pdpt
+        err = get_pdpt(pmap, vaddr, &ptable);
+        table_base = X86_64_PDPT_BASE(vaddr);
+    } else {
+        //normal 4K pages, mapped into ptable
+        err = get_ptable(pmap, vaddr, &ptable);
+        table_base = X86_64_PTABLE_BASE(vaddr);
+    }
     if (err_is_fail(err)) {
         return err_push(err, LIB_ERR_PMAP_GET_PTABLE);
     }
+    assert(ptable->is_vnode);
 
     // check if there is an overlapping mapping
-    if (has_vnode(ptable, X86_64_PTABLE_BASE(vaddr), pte_count)) {
-        printf("page already exists in 0x%"PRIxGENVADDR"--0x%"PRIxGENVADDR"\n", vaddr, vend);
-        return LIB_ERR_PMAP_EXISTING_MAPPING;
+    if (has_vnode(ptable, table_base, pte_count, false)) {
+        if (has_vnode(ptable, table_base, pte_count, true)) {
+            printf("page already exists in 0x%"
+                    PRIxGENVADDR"--0x%"PRIxGENVADDR"\n", vaddr, vend);
+            return LIB_ERR_PMAP_EXISTING_MAPPING;
+        } else {
+            // clean out empty page tables. We do this here because we benefit
+            // from having the page tables in place when doing lots of small
+            // mappings
+            remove_empty_vnodes(pmap, ptable, table_base, pte_count);
+        }
     }
 
     // setup userspace mapping
     struct vnode *page = slab_alloc(&pmap->slab);
     assert(page);
     page->is_vnode = false;
-    page->entry = X86_64_PTABLE_BASE(vaddr);
+    page->entry = table_base;
     page->next  = ptable->u.vnode.children;
     ptable->u.vnode.children = page;
     page->u.frame.cap = frame;
@@ -293,7 +271,7 @@ static errval_t do_single_map(struct pmap_x86 *pmap, genvaddr_t vaddr, genvaddr_
     page->u.frame.pte_count = pte_count;
 
     // do map
-    err = vnode_map(ptable->u.vnode.cap, frame, X86_64_PTABLE_BASE(vaddr),
+    err = vnode_map(ptable->u.vnode.cap, frame, table_base,
                     pmap_flags, offset, pte_count);
     if (err_is_fail(err)) {
         return err_push(err, LIB_ERR_VNODE_MAP);
@@ -311,45 +289,101 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
 {
     errval_t err;
 
-    size = ROUND_UP(size, X86_64_BASE_PAGE_SIZE);
-    size_t pte_count = DIVIDE_ROUND_UP(size, X86_64_BASE_PAGE_SIZE);
+    // determine page size and relevant address part
+    size_t page_size  = X86_64_BASE_PAGE_SIZE;
+    size_t table_base = X86_64_PTABLE_BASE(vaddr);
+    uint8_t map_bits  = X86_64_BASE_PAGE_BITS + X86_64_PTABLE_BITS;
+    bool debug_out    = false;
+
+    // get base address and size of frame
+    struct frame_identity fi;
+    err = invoke_frame_identify(frame, &fi);
+    if (err_is_fail(err)) {
+        return err_push(err, LIB_ERR_PMAP_DO_MAP);
+    }
+
+    if ((flags & VREGION_FLAGS_HUGE) &&
+        (vaddr & X86_64_HUGE_PAGE_MASK) == 0 &&
+        fi.bits >= X86_64_HUGE_PAGE_BITS &&
+        ((fi.base & X86_64_HUGE_PAGE_MASK) == 0))
+    {
+        // huge page branch (1GB)
+        page_size  = X86_64_HUGE_PAGE_SIZE;
+        table_base = X86_64_PDPT_BASE(vaddr);
+        map_bits   = X86_64_HUGE_PAGE_BITS + X86_64_PTABLE_BITS;
+        debug_out  = false;
+        // remove large flag, if we're doing huge mapping
+        flags     &= ~VREGION_FLAGS_LARGE;
+    } else if ((flags & VREGION_FLAGS_LARGE) &&
+               (vaddr & X86_64_LARGE_PAGE_MASK) == 0 &&
+               fi.bits >= X86_64_LARGE_PAGE_BITS &&
+               ((fi.base & X86_64_LARGE_PAGE_MASK) == 0))
+    {
+        // large page branch (2MB)
+        page_size  = X86_64_LARGE_PAGE_SIZE;
+        table_base = X86_64_PDIR_BASE(vaddr);
+        map_bits   = X86_64_LARGE_PAGE_BITS + X86_64_PTABLE_BITS;
+        debug_out  = false;
+    } else {
+        // remove large/huge flags
+        flags &= ~(VREGION_FLAGS_LARGE|VREGION_FLAGS_HUGE);
+    }
+
+    // round to the next full page and calculate end address and #ptes
+    size = ROUND_UP(size, page_size);
+    size_t pte_count = DIVIDE_ROUND_UP(size, page_size);
     genvaddr_t vend = vaddr + size;
 
+    if (offset+size > (1ULL<<fi.bits)) {
+        debug_printf("do_map: offset=%zu; size=%zu; frame size=%zu\n",
+                offset, size, ((size_t)1<<fi.bits));
+        return LIB_ERR_PMAP_FRAME_SIZE;
+    }
+
 #if 0
-    struct frame_identity fi;
-    invoke_frame_identify(frame, &fi);
-    genpaddr_t paddr = fi.base + offset;
+    if (true || debug_out) {
+        genpaddr_t paddr = fi.base + offset;
 
-    debug_printf("do_map: 0x%"
-            PRIxGENVADDR"--0x%"PRIxGENVADDR" -> 0x%"PRIxGENPADDR
-            "; pte_count = %zd; frame bits = %zd\n", vaddr, vend, paddr,
-            pte_count, (size_t)fi.bits);
+        debug_printf("do_map: 0x%"
+                PRIxGENVADDR"--0x%"PRIxGENVADDR" -> 0x%"PRIxGENPADDR
+                "; pte_count = %zd; frame bits = %zd; page size = 0x%zx\n",
+                vaddr, vend, paddr, pte_count, (size_t)fi.bits, page_size);
+    }
 #endif
 
-
-    if (is_same_pdir(vaddr, vend)) {
+    // all mapping on one leaf table?
+    if (is_same_pdir(vaddr, vend) ||
+        (flags & VREGION_FLAGS_LARGE && is_same_pdpt(vaddr, vend)) ||
+        (flags & VREGION_FLAGS_HUGE && is_same_pml4(vaddr, vend))) {
         // fast path
-        //debug_printf("do_map: fast path: %zd\n", pte_count);
+        if (debug_out) {
+            debug_printf("  do_map: fast path: %zd\n", pte_count);
+        }
         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);
         }
-    } else { // multiple leaf page tables
+    }
+    else { // multiple leaf page tables
         // first leaf
-        uint32_t c = X86_64_PTABLE_SIZE - X86_64_PTABLE_BASE(vaddr);
-        //debug_printf("do_map: slow path: first leaf %"PRIu32"\n", c);
-        genvaddr_t temp_end = vaddr + c * X86_64_BASE_PAGE_SIZE;
+        uint32_t c = X86_64_PTABLE_SIZE - table_base;
+        if (debug_out) {
+            debug_printf("  do_map: slow path: first leaf %"PRIu32"\n", c);
+        }
+        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)) {
             return err_push(err, LIB_ERR_PMAP_DO_MAP);
         }
 
         // map full leaves
-        while (get_addr_prefix(temp_end) < get_addr_prefix(vend)) {
+        while (get_addr_prefix(temp_end, map_bits) <
+                get_addr_prefix(vend, map_bits))
+        {
             // update vars
             vaddr = temp_end;
-            temp_end = vaddr + X86_64_PTABLE_SIZE * X86_64_BASE_PAGE_SIZE;
-            offset += c * X86_64_BASE_PAGE_SIZE;
+            temp_end = vaddr + X86_64_PTABLE_SIZE * page_size;
+            offset += c * page_size;
             c = X86_64_PTABLE_SIZE;
             // copy cap
             struct capref next;
@@ -364,16 +398,24 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
             frame = next;
 
             // do mapping
-            //debug_printf("do_map: slow path: full leaf %d\n", X86_64_PTABLE_SIZE);
-            err = do_single_map(pmap, vaddr, temp_end, frame, offset, X86_64_PTABLE_SIZE, flags);
+            if (debug_out) {
+                debug_printf("  do_map: slow path: full leaf\n");
+            }
+            err = do_single_map(pmap, vaddr, temp_end, frame, offset,
+                    X86_64_PTABLE_SIZE, flags);
             if (err_is_fail(err)) {
                 return err_push(err, LIB_ERR_PMAP_DO_MAP);
             }
         }
 
         // map remaining part
-        offset += c * X86_64_BASE_PAGE_SIZE;
-        c = X86_64_PTABLE_BASE(vend) - X86_64_PTABLE_BASE(temp_end);
+        offset += c * page_size;
+
+        // calculate remaining pages (subtract ptable bits from map_bits to
+        // get #ptes of last-level instead of 2nd-to-last).
+        c = get_addr_prefix(vend, map_bits-X86_64_PTABLE_BITS) -
+            get_addr_prefix(temp_end, map_bits-X86_64_PTABLE_BITS);
+
         if (c) {
             // copy cap
             struct capref next;
@@ -387,7 +429,9 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
             }
 
             // do mapping
-            //debug_printf("do_map: slow path: last leaf %"PRIu32"\n", c);
+            if (debug_out) {
+                debug_printf("do_map: slow path: last leaf %"PRIu32"\n", c);
+            }
             err = do_single_map(pmap, temp_end, vend, next, offset, c, flags);
             if (err_is_fail(err)) {
                 return err_push(err, LIB_ERR_PMAP_DO_MAP);
@@ -414,6 +458,21 @@ static size_t max_slabs_for_mapping(size_t bytes)
     return max_pages + max_ptable + max_pdir + max_pdpt;
 }
 
+static size_t max_slabs_for_mapping_large(size_t bytes)
+{
+    size_t max_pages  = DIVIDE_ROUND_UP(bytes, X86_64_LARGE_PAGE_SIZE);
+    size_t max_pdir   = DIVIDE_ROUND_UP(max_pages, X86_64_PTABLE_SIZE);
+    size_t max_pdpt   = DIVIDE_ROUND_UP(max_pdir, X86_64_PTABLE_SIZE);
+    return max_pages  + max_pdir + max_pdpt;
+}
+
+static size_t max_slabs_for_mapping_huge(size_t bytes)
+{
+    size_t max_pages  = DIVIDE_ROUND_UP(bytes, X86_64_HUGE_PAGE_SIZE);
+    size_t max_pdpt   = DIVIDE_ROUND_UP(max_pages, X86_64_PTABLE_SIZE);
+    return max_pages  + max_pdpt;
+}
+
 /**
  * \brief Refill slabs used for metadata
  *
@@ -471,7 +530,7 @@ static errval_t refill_slabs(struct pmap_x86 *pmap, size_t request)
 
         /* Grow the slab */
         lvaddr_t buf = vspace_genvaddr_to_lvaddr(genvaddr);
-        slab_grow(&pmap->slab, (void*)buf, bytes);        
+        slab_grow(&pmap->slab, (void*)buf, bytes);
     }
 
     return SYS_ERR_OK;
@@ -502,16 +561,48 @@ static errval_t map(struct pmap *pmap, genvaddr_t vaddr, struct capref frame,
     errval_t err;
     struct pmap_x86 *x86 = (struct pmap_x86*)pmap;
 
+    struct frame_identity fi;
+    err = invoke_frame_identify(frame, &fi);
+    if (err_is_fail(err)) {
+        return err_push(err, LIB_ERR_PMAP_FRAME_IDENTIFY);
+    }
+
+    size_t max_slabs;
     // Adjust the parameters to page boundaries
-    size   += BASE_PAGE_OFFSET(offset);
-    size    = ROUND_UP(size, BASE_PAGE_SIZE);
-    offset -= BASE_PAGE_OFFSET(offset);
+    // TODO: overestimating needed slabs shouldn't hurt much in the long run,
+    // and would keep the code easier to read and possibly faster due to less
+    // branching
+    if ((flags & VREGION_FLAGS_LARGE) &&
+        (vaddr & X86_64_LARGE_PAGE_MASK) == 0 &&
+        (fi.base & X86_64_LARGE_PAGE_MASK) == 0 &&
+        (1UL<<fi.bits) >= offset+size) {
+        //case large pages (2MB)
+        size   += LARGE_PAGE_OFFSET(offset);
+        size    = ROUND_UP(size, LARGE_PAGE_SIZE);
+        offset -= LARGE_PAGE_OFFSET(offset);
+        max_slabs = max_slabs_for_mapping_large(size);
+    } else if ((flags & VREGION_FLAGS_HUGE) &&
+               (vaddr & X86_64_HUGE_PAGE_MASK) == 0 &&
+               (fi.base & X86_64_HUGE_PAGE_MASK) == 0 &&
+               (1UL<<fi.bits) >= offset+size) {
+        // case huge pages (1GB)
+        size   += HUGE_PAGE_OFFSET(offset);
+        size    = ROUND_UP(size, HUGE_PAGE_SIZE);
+        offset -= HUGE_PAGE_OFFSET(offset);
+        max_slabs = max_slabs_for_mapping_huge(size);
+    } else {
+        //case normal pages (4KB)
+        size   += BASE_PAGE_OFFSET(offset);
+        size    = ROUND_UP(size, BASE_PAGE_SIZE);
+        offset -= BASE_PAGE_OFFSET(offset);
+        max_slabs = max_slabs_for_mapping(size);
+    }
 
     // Refill slab allocator if necessary
     size_t slabs_free = slab_freecount(&x86->slab);
-    size_t max_slabs = max_slabs_for_mapping(size);
+
     max_slabs += 5; // minimum amount required to map a page
-    if (slabs_free < max_slabs) { 
+    if (slabs_free < max_slabs) {
         struct pmap *mypmap = get_current_pmap();
         if (pmap == mypmap) {
             err = refill_slabs(x86, max_slabs);
@@ -533,37 +624,92 @@ static errval_t map(struct pmap *pmap, genvaddr_t vaddr, struct capref frame,
     return err;
 }
 
-static errval_t do_single_unmap(struct pmap_x86 *pmap, genvaddr_t vaddr, size_t pte_count, bool delete_cap)
+/**
+ * \brief Find mapping for `vaddr` in `pmap`.
+ * \arg pmap the pmap to search in
+ * \arg vaddr the virtual address to search for
+ * \arg pt the last-level page table meta-data we found if any
+ * \arg page the page meta-data we found if any
+ * \returns `true` iff we found a mapping for vaddr
+ */
+static bool find_mapping(struct pmap_x86 *pmap, genvaddr_t vaddr,
+                         struct vnode **outpt, struct vnode **outpage)
 {
-    errval_t err;
-    struct vnode *pt = find_ptable(pmap, vaddr);
-    if (pt) {
-        struct vnode *page = find_vnode(pt, X86_64_PTABLE_BASE(vaddr));
-        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)) {
-                printf("vnode_unmap returned error: %s (%d)\n", err_getstring(err), err_no(err));
-                return err_push(err, LIB_ERR_VNODE_UNMAP);
+    struct vnode *pdpt = NULL, *pdir = NULL, *pt = NULL, *page = NULL;
+
+    // find page and last-level page table (can be pdir or pdpt)
+    if ((pdpt = find_pdpt(pmap, vaddr)) != NULL) {
+        page = find_vnode(pdpt, X86_64_PDPT_BASE(vaddr));
+        if (page && page->is_vnode) { // not 1G pages
+            pdir = page;
+            page = find_vnode(pdir, X86_64_PDIR_BASE(vaddr));
+            if (page && page->is_vnode) { // not 2M pages
+                pt = page;
+                page = find_vnode(pt, X86_64_PTABLE_BASE(vaddr));
+            } else if (page) {
+                pt = pdir;
             }
+        } else if (page) {
+            pt = pdpt;
+        }
+    }
+    if (outpt) {
+        *outpt = pt;
+    }
+    if (outpage) {
+        *outpage = page;
+    }
+    if (pt && page) {
+        return true;
+    } else {
+        return false;
+    }
+}
 
-            // Free up the resources
-            if (delete_cap) {
-                err = cap_destroy(page->u.frame.cap);
-                if (err_is_fail(err)) {
-                    return err_push(err, LIB_ERR_PMAP_DO_SINGLE_UNMAP);
-                }
-            }
-            remove_vnode(pt, page);
-            slab_free(&pmap->slab, page);
+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 = NULL, *page = NULL;
+
+    if (!find_mapping(pmap, vaddr, &pt, &page)) {
+        return LIB_ERR_PMAP_FIND_VNODE;
+    }
+    assert(pt && pt->is_vnode && page && !page->is_vnode);
+
+    if (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)) {
+            printf("vnode_unmap returned error: %s (%d)\n",
+                    err_getstring(err), err_no(err));
+            return err_push(err, LIB_ERR_VNODE_UNMAP);
         }
-        else {
-            return LIB_ERR_PMAP_FIND_VNODE;
+
+        // Free up the resources
+        if (delete_cap) {
+            err = cap_destroy(page->u.frame.cap);
+            if (err_is_fail(err)) {
+                printf("delete_cap\n");
+                return err_push(err, LIB_ERR_PMAP_DO_SINGLE_UNMAP);
+            }
         }
+        remove_vnode(pt, page);
+        slab_free(&pmap->slab, page);
     }
 
     return SYS_ERR_OK;
 }
 
+static inline bool is_large_page(struct vnode *p)
+{
+    return !p->is_vnode && p->u.frame.flags & VREGION_FLAGS_LARGE;
+}
+static inline bool is_huge_page(struct vnode *p)
+{
+    return !p->is_vnode && p->u.frame.flags & VREGION_FLAGS_HUGE;
+}
+
 /**
  * \brief Remove page mappings
  *
@@ -578,40 +724,79 @@ 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_64_BASE_PAGE_SIZE);
+
+    //determine if we unmap a larger page
+    struct vnode* page = NULL;
+
+    if (!find_mapping(x86, vaddr, NULL, &page)) {
+        //TODO: better error --> LIB_ERR_PMAP_NOT_MAPPED
+        return LIB_ERR_PMAP_UNMAP;
+    }
+
+    assert(!page->is_vnode);
+
+    size_t page_size = X86_64_BASE_PAGE_SIZE;
+    size_t table_base = X86_64_PTABLE_BASE(vaddr);
+    uint8_t map_bits= X86_64_BASE_PAGE_BITS + X86_64_PTABLE_BITS;
+    if (is_large_page(page)) {
+        //large 2M page
+        page_size = X86_64_LARGE_PAGE_SIZE;
+        table_base = X86_64_PDIR_BASE(vaddr);
+        map_bits = X86_64_LARGE_PAGE_BITS + X86_64_PTABLE_BITS;
+    } else if (is_huge_page(page)) {
+        //huge 1GB page
+        page_size = X86_64_HUGE_PAGE_SIZE;
+        table_base = X86_64_PDPT_BASE(vaddr);
+        map_bits = X86_64_HUGE_PAGE_BITS + X86_64_PTABLE_BITS;
+    }
+
+    // TODO: match new policy of map when implemented
+    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) && is_large_page(page)) ||
+        (is_same_pml4(vaddr, vend) && is_huge_page(page)))
+    {
         // fast path
-        err = do_single_unmap(x86, vaddr, size / X86_64_BASE_PAGE_SIZE, false);
-        if (err_is_fail(err)) {
+        err = do_single_unmap(x86, vaddr, size / page_size, false);
+        if (err_is_fail(err) && err_no(err) != LIB_ERR_PMAP_FIND_VNODE) {
+            printf("error fast path\n");
             return err_push(err, LIB_ERR_PMAP_UNMAP);
         }
     }
     else { // slow path
         // unmap first leaf
-        uint32_t c = X86_64_PTABLE_SIZE - X86_64_PTABLE_BASE(vaddr);
+        uint32_t c = X86_64_PTABLE_SIZE - table_base;
+
         err = do_single_unmap(x86, vaddr, c, false);
-        if (err_is_fail(err)) {
+        if (err_is_fail(err) && err_no(err) != LIB_ERR_PMAP_FIND_VNODE) {
+            printf("error first leaf\n");
             return err_push(err, LIB_ERR_PMAP_UNMAP);
         }
 
         // unmap full leaves
-        vaddr += c * X86_64_BASE_PAGE_SIZE;
-        while (get_addr_prefix(vaddr) < get_addr_prefix(vend)) {
+        vaddr += c * page_size;
+        while (get_addr_prefix(vaddr, map_bits) < get_addr_prefix(vend, map_bits)) {
             c = X86_64_PTABLE_SIZE;
             err = do_single_unmap(x86, vaddr, X86_64_PTABLE_SIZE, true);
-            if (err_is_fail(err)) {
+            if (err_is_fail(err) && err_no(err) != LIB_ERR_PMAP_FIND_VNODE) {
+                printf("error while loop\n");
                 return err_push(err, LIB_ERR_PMAP_UNMAP);
             }
-            vaddr += c * X86_64_BASE_PAGE_SIZE;
+            vaddr += c * page_size;
         }
 
         // unmap remaining part
-        c = X86_64_PTABLE_BASE(vend) - X86_64_PTABLE_BASE(vaddr);
+        // subtracting ptable bits from map_bits to get #ptes in last-level table
+        // instead of 2nd-to-last.
+        c = get_addr_prefix(vend, map_bits-X86_64_PTABLE_BITS) -
+            get_addr_prefix(vaddr, map_bits-X86_64_PTABLE_BITS);
+        assert(c < X86_64_PTABLE_SIZE);
         if (c) {
             err = do_single_unmap(x86, vaddr, c, true);
-            if (err_is_fail(err)) {
+            if (err_is_fail(err) && err_no(err) != LIB_ERR_PMAP_FIND_VNODE) {
+                printf("error remaining part\n");
                 return err_push(err, LIB_ERR_PMAP_UNMAP);
             }
         }
@@ -638,8 +823,8 @@ static errval_t do_single_modify_flags(struct pmap_x86 *pmap, genvaddr_t vaddr,
                 // we're modifying part of a valid mapped region
                 // arguments to invocation: invoke frame cap, first affected
                 // page (as offset from first page in mapping), #affected
-                // pages, new flags. Invocation should check compatibility of
-                // new set of flags with cap permissions.
+                // pages, new flags. Invocation mask flags based on capability
+                // access permissions.
                 size_t off = ptentry - page->entry;
                 paging_x86_64_flags_t pmap_flags = vregion_to_pmap_flag(flags);
                 err = invoke_frame_modify_flags(page->u.frame.cap, off, pages, pmap_flags);
@@ -675,6 +860,9 @@ static errval_t modify_flags(struct pmap *pmap, genvaddr_t vaddr, size_t size,
 
     // vaddr and vend specify begin and end of the region (inside a mapping)
     // that should receive the new set of flags
+    //
+    // TODO: figure out page_size etc of original mapping
+    uint8_t map_bits = X86_64_BASE_PAGE_BITS + X86_64_PTABLE_BITS;
 
     if (is_same_pdir(vaddr, vend)) {
         // fast path
@@ -693,7 +881,7 @@ static errval_t modify_flags(struct pmap *pmap, genvaddr_t vaddr, size_t size,
 
         // modify full leaves
         vaddr += c * X86_64_BASE_PAGE_SIZE;
-        while (get_addr_prefix(vaddr) < get_addr_prefix(vend)) {
+        while (get_addr_prefix(vaddr, map_bits) < get_addr_prefix(vend, map_bits)) {
             c = X86_64_PTABLE_SIZE;
             err = do_single_modify_flags(x86, vaddr, X86_64_PTABLE_SIZE, flags);
             if (err_is_fail(err)) {
@@ -740,14 +928,20 @@ static errval_t lookup(struct pmap *pmap, genvaddr_t vaddr,
 {
     struct pmap_x86 *x86 = (struct pmap_x86 *)pmap;
 
+    uint32_t base = X86_64_PTABLE_BASE(vaddr);
     // Find the page table
     struct vnode *ptable = find_ptable(x86, vaddr);
     if (ptable == NULL) {
-        return LIB_ERR_PMAP_FIND_VNODE;
+        //mapped in pdir?
+        ptable = find_pdir(x86, vaddr);
+        if (ptable == NULL) {
+            return LIB_ERR_PMAP_FIND_VNODE;
+        }
+        base = X86_64_PDIR_BASE(vaddr);
     }
 
     // Find the page
-    struct vnode *vn = find_vnode(ptable, X86_64_PTABLE_BASE(vaddr));
+    struct vnode *vn = find_vnode(ptable, base);
     if (vn == NULL) {
         return LIB_ERR_PMAP_FIND_VNODE;
     }
@@ -775,6 +969,8 @@ static errval_t lookup(struct pmap *pmap, genvaddr_t vaddr,
     return SYS_ERR_OK;
 }
 
+
+
 static errval_t dump(struct pmap *pmap, struct pmap_dump_info *buf, size_t buflen, size_t *items_written)
 {
     struct pmap_x86 *x86 = (struct pmap_x86 *)pmap;
@@ -816,8 +1012,55 @@ static errval_t dump(struct pmap *pmap, struct pmap_dump_info *buf, size_t bufle
     return SYS_ERR_OK;
 }
 
+static errval_t determine_addr_raw(struct pmap *pmap, size_t size,
+                                   size_t alignment, genvaddr_t *retvaddr)
+{
+    struct pmap_x86 *x86 = (struct pmap_x86 *)pmap;
+
+    struct vnode *walk_pml4 = x86->root.u.vnode.children;
+    assert(walk_pml4 != 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);
+    assert(size < 512ul * 1024 * 1024 * 1024); // pml4 size
+
+    // try to find free pml4 entry
+    bool f[512];
+    for (int i = 0; i < 512; i++) {
+        f[i] = true;
+    }
+    //debug_printf("entry: %d\n", walk_pml4->entry);
+    f[walk_pml4->entry] = false;
+    while (walk_pml4) {
+        //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]);
+        if (f[first_free]) {
+            break;
+        }
+    }
+    //debug_printf("first_free: %"PRIuGENVADDR"\n", first_free);
+    if (first_free < 512) {
+        //debug_printf("first_free: %"PRIuGENVADDR"\n", first_free);
+        *retvaddr = first_free << 39;
+        return SYS_ERR_OK;
+    } else {
+        return LIB_ERR_OUT_OF_VIRTUAL_ADDR;
+    }
+}
+
 static struct pmap_funcs pmap_funcs = {
     .determine_addr = pmap_x86_determine_addr,
+    .determine_addr_raw = determine_addr_raw,
     .map = map,
     .unmap = unmap,
     .lookup = lookup,
@@ -863,7 +1106,7 @@ errval_t pmap_x86_64_init(struct pmap *pmap, struct vspace *vspace,
     // pointer derefs with suitably large offsets
     x86->min_mappable_va = 64 * 1024;
 
-    // maximum mappable VA is drived from X86_64_MEMORY_OFFSET in kernel
+    // maximum mappable VA is derived from X86_64_MEMORY_OFFSET in kernel
     x86->max_mappable_va = (genvaddr_t)0xffffff8000000000;
 
     return SYS_ERR_OK;
index 1a94c55..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>
@@ -329,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 {
index 2f5be8f..ea38369 100644 (file)
@@ -8,16 +8,18 @@
 
 /*
  * Copyright (c) 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 <barrelfish/vspace_mmu_aware.h>
 #include <barrelfish/core_state.h>
+#include <string.h>
 
 /// Minimum free memory before we return it to memory server
 #define MIN_MEM_FOR_FREE        (1 * 1024 * 1024)
  */
 errval_t vspace_mmu_aware_init(struct vspace_mmu_aware *state, size_t size)
 {
+    return vspace_mmu_aware_init_aligned(state, size, 0,
+            VREGION_FLAGS_READ_WRITE);
+}
+
+errval_t vspace_mmu_aware_init_aligned(struct vspace_mmu_aware *state,
+        size_t size, size_t alignment, vregion_flags_t flags)
+{
     state->size = size;
     state->consumed = 0;
+    state->alignment = alignment;
 
     errval_t err;
 
@@ -44,9 +54,9 @@ errval_t vspace_mmu_aware_init(struct vspace_mmu_aware *state, size_t size)
         return err_push(err, LIB_ERR_MEMOBJ_CREATE_ANON);
     }
 
-    err = vregion_map(&state->vregion, get_current_vspace(),
-                      &state->memobj.m, 0, size,
-                      VREGION_FLAGS_READ_WRITE);
+    err = vregion_map_aligned(&state->vregion, get_current_vspace(),
+                              &state->memobj.m, 0, size,
+                              flags, alignment);
     if (err_is_fail(err)) {
         return err_push(err, LIB_ERR_VREGION_MAP);
     }
@@ -83,13 +93,29 @@ errval_t vspace_mmu_aware_map(struct vspace_mmu_aware *state,
     } else {
         req_size -= state->mapoffset - state->offset;
     }
+    size_t alloc_size = req_size;
     size_t ret_size = 0;
 
-    if(req_size > 0) {
+    if (req_size > 0) {
+        if ((state->mapoffset & LARGE_PAGE_MASK) == 0 &&
+            state->alignment >= LARGE_PAGE_SIZE)
+        {
+            // this is an opportunity to switch to 2M pages
+            // we know that we can use large pages without jumping through hoops
+            // if state->alignment is at least LARGE_PAGE_SIZE as we always create
+            // the vregion with VREGION_FLAGS_LARGE.
+            alloc_size = ROUND_UP(req_size, LARGE_PAGE_SIZE);
+        }
         // Create frame of appropriate size
-        err = frame_create(frame, req_size, &ret_size);
+retry:
+        err = frame_create(frame, alloc_size, &ret_size);
         if (err_is_fail(err)) {
             if (err_no(err) == LIB_ERR_RAM_ALLOC_MS_CONSTRAINTS) {
+                // we can only get 4k frames for now; retry with 4k
+                if (alloc_size > BASE_PAGE_SIZE && origsize < BASE_PAGE_SIZE) {
+                    alloc_size = BASE_PAGE_SIZE;
+                    goto retry;
+                }
                 return err_push(err, LIB_ERR_FRAME_CREATE_MS_CONSTRAINTS);
             }
             return err_push(err, LIB_ERR_FRAME_CREATE);
@@ -131,6 +157,74 @@ errval_t vspace_mmu_aware_map(struct vspace_mmu_aware *state,
     return SYS_ERR_OK;
 }
 
+errval_t vspace_mmu_aware_reset(struct vspace_mmu_aware *state,
+                                struct capref frame, size_t size)
+{
+    errval_t err;
+    struct vregion *vregion;
+    struct capref oldframe;
+    void *vbuf;
+    // create copy of new region
+    err = slot_alloc(&oldframe);
+    if (err_is_fail(err)) {
+        return err;
+    }
+    err = cap_copy(oldframe, frame);
+    if (err_is_fail(err)) {
+        return err;
+    }
+    err = vspace_map_one_frame_attr_aligned(&vbuf, size, oldframe,
+            VREGION_FLAGS_READ_WRITE | VREGION_FLAGS_LARGE, LARGE_PAGE_SIZE,
+            NULL, &vregion);
+    if (err_is_fail(err)) {
+        return err;
+    }
+    // copy over data to new frame
+    genvaddr_t gen_base = vregion_get_base_addr(&state->vregion);
+    memcpy(vbuf, (void*)gen_base, state->mapoffset);
+
+    err = vregion_destroy(vregion);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    size_t offset = 0;
+    // Unmap backing frames for [0, size) in state.vregion
+    do {
+        err = state->memobj.m.f.unfill(&state->memobj.m, 0, &oldframe,
+                &offset);
+        if (err_is_fail(err) &&
+            err_no(err) != LIB_ERR_MEMOBJ_UNFILL_TOO_HIGH_OFFSET)
+        {
+            return err_push(err, LIB_ERR_MEMOBJ_UNMAP_REGION);
+        }
+        struct frame_identity fi;
+        // increase address
+        err = invoke_frame_identify(oldframe, &fi);
+        if (err_is_fail(err)) {
+            return err;
+        }
+        offset += (1UL<<fi.bits);
+        err = cap_destroy(oldframe);
+        if (err_is_fail(err)) {
+            return err;
+        }
+    } while(offset < state->mapoffset);
+
+    // Map new frame in
+    err = state->memobj.m.f.fill(&state->memobj.m, 0, frame, size);
+    if (err_is_fail(err)) {
+        return err_push(err, LIB_ERR_MEMOBJ_FILL);
+    }
+    err = state->memobj.m.f.pagefault(&state->memobj.m, &state->vregion, 0, 0);
+    if (err_is_fail(err)) {
+        return err_push(err, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
+    }
+
+    state->mapoffset = size;
+    return SYS_ERR_OK;
+}
+
 errval_t vspace_mmu_aware_unmap(struct vspace_mmu_aware *state,
                                 lvaddr_t base, size_t bytes)
 {
@@ -144,11 +238,11 @@ errval_t vspace_mmu_aware_unmap(struct vspace_mmu_aware *state,
     genvaddr_t min_offset = 0;
     bool success = false;
 
-    assert(vspace_lvaddr_to_genvaddr(base) > vregion_get_base_addr(&state->vregion));
+    assert(vspace_lvaddr_to_genvaddr(base) >= vregion_get_base_addr(&state->vregion));
     assert(base + bytes == (lvaddr_t)eaddr);
 
-    assert(bytes < state->consumed);
-    assert(bytes < state->offset);
+    assert(bytes <= state->consumed);
+    assert(bytes <= state->offset);
 
     // Reduce offset
     state->offset -= bytes;
index a652c98..3a6ed0b 100644 (file)
@@ -5,11 +5,12 @@
 
 /*
  * 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>
@@ -115,10 +116,10 @@ errval_t vspace_map_anon_aligned(void **retaddr, struct memobj **ret_memobj,
         free(memobj);
         free(vregion);
     }
-    
+
     *ret_memobj = (struct memobj *)memobj;
     *ret_vregion = vregion;
-    
+
     return err;
 }
 
@@ -136,7 +137,7 @@ errval_t vspace_map_anon_attr(void **retaddr, struct memobj **ret_memobj,
 
     struct memobj_anon *memobj = NULL;
     struct vregion *vregion = NULL;
-    
+
     // Allocate space
     memobj = malloc(sizeof(struct memobj_anon));
     assert(memobj != NULL);
@@ -151,10 +152,10 @@ errval_t vspace_map_anon_attr(void **retaddr, struct memobj **ret_memobj,
       free(memobj);
       free(vregion);
     }
-    
+
     *ret_memobj = (struct memobj *)memobj;
     *ret_vregion = vregion;
-    
+
     return err;
 }
 
@@ -324,6 +325,20 @@ errval_t vspace_map_one_frame_attr(void **retaddr, size_t size,
                                    struct memobj **retmemobj,
                                    struct vregion **retvregion)
 {
+    return vspace_map_one_frame_attr_aligned(retaddr, size,
+            frame, flags, 0, retmemobj, retvregion);
+}
+
+/**
+ * \brief Wrapper for creating and mapping a memory object
+ * of type one frame with specific flags and a specific alignment
+ */
+errval_t vspace_map_one_frame_attr_aligned(void **retaddr, size_t size,
+                                   struct capref frame, vregion_flags_t flags,
+                                   size_t alignment,
+                                   struct memobj **retmemobj,
+                                   struct vregion **retvregion)
+{
     errval_t err1, err2;
     struct memobj *memobj   = NULL;
     struct vregion *vregion = NULL;
@@ -331,12 +346,12 @@ errval_t vspace_map_one_frame_attr(void **retaddr, size_t size,
     size = ROUND_UP(size, BASE_PAGE_SIZE);
 
     // Allocate space
-    memobj = malloc(sizeof(struct memobj_one_frame));
+    memobj = calloc(1, sizeof(struct memobj_one_frame));
     if (!memobj) {
         err1 = LIB_ERR_MALLOC_FAIL;
         goto error;
     }
-    vregion = malloc(sizeof(struct vregion));
+    vregion = calloc(1, sizeof(struct vregion));
     if (!vregion) {
         err1 = LIB_ERR_MALLOC_FAIL;
         goto error;
@@ -355,7 +370,8 @@ errval_t vspace_map_one_frame_attr(void **retaddr, size_t size,
         goto error;
     }
 
-    err1 = vregion_map(vregion, get_current_vspace(), memobj, 0, size, flags);
+    err1 = vregion_map_aligned(vregion, get_current_vspace(), memobj, 0, size,
+            flags, alignment);
     if (err_is_fail(err1)) {
         err1 = err_push(err1, LIB_ERR_VREGION_MAP);
         goto error;
index 2227943..1171333 100644 (file)
@@ -8,6 +8,7 @@
 
 /*
  * Copyright (c) 2009, 2010, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
@@ -60,6 +61,10 @@ errval_t vregion_map_aligned(struct vregion *vregion, struct vspace* vspace,
     // Add to memobj
     err = memobj->f.map_region(memobj, vregion);
     if (err_is_fail(err)) {
+        // remove memobj from region if map fails, otherwise we'll get a
+        // follow up error if client code call vregion_destroy() on the
+        // region.
+        vregion->memobj = NULL;
         return err_push(err, LIB_ERR_MEMOBJ_MAP_REGION);
     }
 
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/tests/argtest/Hakefile b/usr/tests/argtest/Hakefile
new file mode 100644 (file)
index 0000000..f13d33f
--- /dev/null
@@ -0,0 +1,16 @@
+--------------------------------------------------------------------------
+-- 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, Universitaetstr 6, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for /usr/tests/argtest
+--
+-- Argument parsing test.
+--
+--------------------------------------------------------------------------
+
+[ build application { target = "argtest", cFiles = [ "argtest.c" ] }
+]
diff --git a/usr/tests/argtest/argtest.c b/usr/tests/argtest/argtest.c
new file mode 100644 (file)
index 0000000..6b84c28
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * \file
+ * \brief arguments test.
+ */
+
+/*
+ * 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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+    for (int i = 0; i < argc; i++) {
+        printf("argv[%d] = %s\n", i, argv[i]);
+    }
+    return 0;
+}
diff --git a/usr/tests/large_page/Hakefile b/usr/tests/large_page/Hakefile
new file mode 100644 (file)
index 0000000..e5568d8
--- /dev/null
@@ -0,0 +1,27 @@
+--------------------------------------------------------------------------
+-- 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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for /usr/tests/large_page
+-- 
+--------------------------------------------------------------------------
+
+[ build application { target = "test_large_mappings",
+                      cFiles = [ "map_test.c" ],
+                      architectures = [ "x86_64" ]
+                    },
+ build application { target = "test_large_malloc",
+                      cFiles = [ "malloc_test.c" ],
+                      architectures = [ "x86_64" ]
+                    },
+  build application { target = "test_large_mappings",
+                      cFiles = [ "map_test_32.c" ],
+                      architectures = [ "x86_32" ]
+                    }
+
+]
+
diff --git a/usr/tests/large_page/malloc_test.c b/usr/tests/large_page/malloc_test.c
new file mode 100644 (file)
index 0000000..0bb1433
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * \file
+ * \brief Test program for large page code
+ */
+
+/*
+ * 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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/sys_debug.h>
+
+#define RUNS 2
+// 128MB buffer
+#define BUFSIZE (128UL*1024*1024)
+
+int main(void)
+{
+    void *bufs[RUNS];
+    for (int k = 0; k < RUNS; k++) {
+        // touch every 4k page in region
+        bufs[k] = malloc(BUFSIZE);
+        uint8_t *buf = bufs[k];
+        for (int i = 0; i < BUFSIZE / X86_64_BASE_PAGE_SIZE; i++) {
+            buf[i*BASE_PAGE_SIZE] = i % 256;
+        }
+        // clear out caches
+        sys_debug_flush_cache();
+        int errors = 0;
+        for (int i = 0; i < BUFSIZE / X86_64_BASE_PAGE_SIZE; i++) {
+            if (buf[i*BASE_PAGE_SIZE] != i % 256) {
+                debug_printf("mismatch in page %d: expected %d, was %d\n",
+                        i, i % 256, buf[i*BASE_PAGE_SIZE]);
+                errors++;
+            }
+        }
+        debug_printf("test %s\n", errors ? "FAILED" : "PASSED");
+        if (errors) {
+            debug_printf("  %d errors\n", errors);
+        }
+    }
+    for (int k = 0; k < RUNS; k++) {
+        debug_printf("bufs[%d] = %p\n", k, bufs[k]);
+    }
+    debug_dump_hw_ptables();
+    for (int k = 0; k < RUNS; k++) {
+        free(bufs[k]);
+    }
+    return 0;
+}
diff --git a/usr/tests/large_page/map_test.c b/usr/tests/large_page/map_test.c
new file mode 100644 (file)
index 0000000..866b6dd
--- /dev/null
@@ -0,0 +1,142 @@
+/**
+ * \file
+ * \brief Test program for large page code
+ */
+
+/*
+ * 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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/sys_debug.h>
+
+#define RUNS 2
+
+int main(void)
+{
+    errval_t err;
+    struct capref frame;
+    size_t retsize;
+    void *vbuf;
+    struct vregion *vregion;
+    uint8_t *buf;
+    int errors;
+
+    // get frame
+    err = frame_alloc(&frame, X86_64_HUGE_PAGE_SIZE, &retsize);
+    assert(retsize >= X86_64_HUGE_PAGE_SIZE);
+    if (err_is_fail(err)) {
+        debug_printf("frame_alloc: %s\n", err_getstring(err));
+        return 1;
+    }
+
+    for (int k = 0; k < RUNS; k++) {
+        debug_printf("Running 2M/1G test\n");
+        // map with alignment and large flag (don't need memobj)
+        err = vspace_map_one_frame_attr_aligned(&vbuf, retsize, frame,
+                VREGION_FLAGS_READ_WRITE | VREGION_FLAGS_LARGE,
+                X86_64_HUGE_PAGE_SIZE, NULL, &vregion);
+        if (err_is_fail(err)) {
+            debug_printf("vspace_map: %s\n", err_getstring(err));
+            return 1;
+        }
+
+        debug_printf("vaddr: %p\n", vbuf);
+
+        // touch every 4k page in region
+        buf = vbuf;
+        for (int i = 0; i < X86_64_HUGE_PAGE_SIZE / X86_64_BASE_PAGE_SIZE; i++) {
+            buf[i*BASE_PAGE_SIZE] = i % 256;
+        }
+        // clear out caches
+        sys_debug_flush_cache();
+        errors = 0;
+        for (int i = 0; i < X86_64_HUGE_PAGE_SIZE / X86_64_BASE_PAGE_SIZE; i++) {
+            if (buf[i*BASE_PAGE_SIZE] != i % 256) {
+                debug_printf("mismatch in page %d: expected %d, was %d\n",
+                        i, i % 256, buf[i*BASE_PAGE_SIZE]);
+                errors++;
+            }
+        }
+        debug_printf("2M/1G test %s\n", errors ? "FAILED" : "PASSED");
+        if (errors) {
+            debug_printf("  %d errors\n", errors);
+        }
+
+        vregion_destroy(vregion);
+    }
+    for (int k = 0; k < RUNS; k++) {
+        debug_printf("Running 2M/2M test\n");
+        // map with large flag
+        err = vspace_map_one_frame_attr_aligned(&vbuf, retsize, frame,
+                VREGION_FLAGS_READ_WRITE | VREGION_FLAGS_LARGE,
+                X86_64_LARGE_PAGE_SIZE, NULL, &vregion);
+        if (err_is_fail(err)) {
+            debug_printf("vspace_map: %s\n", err_getstring(err));
+            return 1;
+        }
+
+        debug_printf("vaddr: %p\n", vbuf);
+
+        // touch every 4k page in region
+        buf = vbuf;
+        for (int i = 0; i < X86_64_HUGE_PAGE_SIZE / X86_64_BASE_PAGE_SIZE; i++) {
+            buf[i*BASE_PAGE_SIZE] = i % 256;
+        }
+        // clear out caches
+        sys_debug_flush_cache();
+        errors = 0;
+        for (int i = 0; i < X86_64_HUGE_PAGE_SIZE / X86_64_BASE_PAGE_SIZE; i++) {
+            if (buf[i*BASE_PAGE_SIZE] != i % 256) {
+                debug_printf("mismatch in page %d: expected %d, was %d\n",
+                        i, i % 256, buf[i*BASE_PAGE_SIZE]);
+                errors++;
+            }
+        }
+        debug_printf("2M/2M test %s\n", errors ? "FAILED" : "PASSED");
+        if (errors) {
+            debug_printf("  %d errors\n", errors);
+        }
+
+        vregion_destroy(vregion);
+    }
+
+    uint32_t eax, ebx, ecx, edx;
+    cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+    if ((edx >> 26) & 1) {
+        debug_printf("Running 1G/1G test\n");
+        err = vspace_map_one_frame_attr_aligned(&vbuf, retsize, frame,
+                VREGION_FLAGS_READ_WRITE | VREGION_FLAGS_HUGE,
+                X86_64_HUGE_PAGE_SIZE, NULL, &vregion);
+        if (err_is_fail(err)) {
+            debug_printf("vspace_map: %s\n", err_getstring(err));
+            return 1;
+        }
+
+        // touch every 4k page in region
+        buf = vbuf;
+        for (int i = 0; i < X86_64_HUGE_PAGE_SIZE / X86_64_BASE_PAGE_SIZE; i++) {
+            buf[i*BASE_PAGE_SIZE] = i % 256;
+        }
+        // clear out caches
+        sys_debug_flush_cache();
+        errors = 0;
+        for (int i = 0; i < X86_64_HUGE_PAGE_SIZE / X86_64_BASE_PAGE_SIZE; i++) {
+            if (buf[i*BASE_PAGE_SIZE] != i % 256) {
+                debug_printf("mismatch in page %d: expected %d, was %d\n",
+                        i, i % 256, buf[i*BASE_PAGE_SIZE]);
+                errors++;
+            }
+        }
+        debug_printf("1G/1G test %s\n", errors ? "FAILED" : "PASSED");
+        if (errors) {
+            debug_printf("  %d errors\n", errors);
+        }
+    }
+    return 0;
+}
diff --git a/usr/tests/large_page/map_test_32.c b/usr/tests/large_page/map_test_32.c
new file mode 100644 (file)
index 0000000..5402cd1
--- /dev/null
@@ -0,0 +1,81 @@
+/**
+ * \file
+ * \brief Test program for large page code
+ */
+
+/*
+ * 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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/sys_debug.h>
+
+#define RUNS 2
+#define PAGE_COUNT 64
+#define TOTAL_SIZE (PAGE_COUNT * LARGE_PAGE_SIZE)
+
+int main(void)
+{
+#if !defined(CONFIG_PSE)
+    debug_printf("PSE not enabled, change Config.hs and rebuild.\n");
+    return 0;
+#endif
+    errval_t err;
+    struct capref frame;
+    size_t retsize;
+    void *vbuf;
+    struct vregion *vregion;
+    uint8_t *buf;
+    int errors;
+
+    // get frame
+    err = frame_alloc(&frame, TOTAL_SIZE, &retsize);
+    assert(retsize >= TOTAL_SIZE);
+    if (err_is_fail(err)) {
+        debug_printf("frame_alloc: %s\n", err_getstring(err));
+        return 1;
+    }
+
+    for (int k = 0; k < RUNS; k++) {
+        debug_printf("Running large page test\n");
+        // map with alignment and huge flag (don't need memobj and vregion)
+        err = vspace_map_one_frame_attr_aligned(&vbuf, retsize, frame,
+                VREGION_FLAGS_READ_WRITE | VREGION_FLAGS_LARGE,
+                TOTAL_SIZE, NULL, &vregion);
+        if (err_is_fail(err)) {
+            debug_printf("vspace_map: %s\n", err_getstring(err));
+            return 1;
+        }
+
+        debug_printf("vaddr: %p\n", vbuf);
+
+        // touch every 4k page in region
+        buf = vbuf;
+        for (int i = 0; i < TOTAL_SIZE / BASE_PAGE_SIZE; i++) {
+            buf[i*BASE_PAGE_SIZE] = i % 256;
+        }
+        // clear out caches
+        sys_debug_flush_cache();
+        errors = 0;
+        for (int i = 0; i < TOTAL_SIZE / BASE_PAGE_SIZE; i++) {
+            if (buf[i*BASE_PAGE_SIZE] != i % 256) {
+                debug_printf("mismatch in page %d: expected %d, was %d\n",
+                        i, i % 256, buf[i*BASE_PAGE_SIZE]);
+                errors++;
+            }
+        }
+        debug_printf("large page test %s\n", errors ? "FAILED" : "PASSED");
+        if (errors) {
+            debug_printf("  %d errors\n", errors);
+        }
+
+        vregion_destroy(vregion);
+    }
+
+    return 0;
+}
index 9e9ebc0..e5e7a60 100644 (file)
@@ -1,5 +1,6 @@
 --------------------------------------------------------------------------
 -- Copyright (c) 2007-2009, 2011, ETH Zurich.
+-- Copyright (c) 2014, HP Labs.
 -- All rights reserved.
 --
 -- This file is distributed under the terms in the attached LICENSE file.
@@ -18,5 +19,8 @@
                     },
   build application { target = "test_modify_flags",
                       cFiles = [ "modify_flags.c" ]
+                    },
+  build application { target = "test_invalid_mappings",
+                      cFiles = [ "invalid_mappings.c" ]
                     }
 ]
diff --git a/usr/tests/nkm/invalid_mappings.c b/usr/tests/nkm/invalid_mappings.c
new file mode 100644 (file)
index 0000000..d8d0823
--- /dev/null
@@ -0,0 +1,145 @@
+/**
+ * \file
+ * \brief Test invalid vnode invocations.
+ */
+
+/*
+ * 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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/cap_predicates.h>
+#include <stdio.h>
+
+#define FRAME_ACCESS_DEFAULT \
+        (PTABLE_USER_SUPERVISOR | PTABLE_EXECUTE_DISABLE | PTABLE_READ_WRITE)
+
+static enum objtype types[7] =
+{
+    ObjType_VNode_x86_64_pml4,
+    ObjType_VNode_x86_64_pdpt,
+    ObjType_VNode_x86_64_pdir,
+    ObjType_VNode_x86_64_ptable,
+    ObjType_Frame,
+    ObjType_Frame,
+    ObjType_Frame
+};
+
+static bool mapping_ok[4][7] =
+{         /*pml4*/ /*pdpt*/ /*pdir*/ /*pt*/ /*frm*/ /*2mfrm*/ /*1gfrm*/
+/*pml4*/{   0,       1,       0,       0,     0,      0,        0  },
+/*pdpt*/{   0,       0,       1,       0,     0,      0,        1  },
+/*pdir*/{   0,       0,       0,       1,     0,      1,        1  },
+/*pt  */{   0,       0,       0,       0,     1,      1,        1  },
+};
+
+static int pass = 0, fail = 0;
+static void check_result(errval_t err, int dest, int src)
+{
+    if (err_is_ok(err) && mapping_ok[dest][src]) {
+        printf("%d<-%d PASSED (%s)\n", dest, src, err_getstring(err));
+        pass++;
+    } else if (err_is_fail(err) && !mapping_ok[dest][src]) {
+        printf("%d<-%d PASSED (%s)\n", dest, src, err_getstring(err));
+        pass++;
+    } else {
+        printf("%d<-%d FAILED (expected: %d, was %s)\n",
+                dest, src, mapping_ok[dest][src], err_getstring(err));
+        fail++;
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    // outline:
+    // get pml4, pdpt, pdir, ptable, and frame
+    // check all combinations to make sure that restrictions are implemented
+    // correctly in kernel space
+    // VALID:
+    // map pdpt in pml4
+    // map pdir in pdpt
+    // map pt   in pdir
+    // map frame in {pt, pdir, pdpt}
+    // INVALID:
+    // all other combinations
+
+    errval_t err;
+    struct capref caps[7];
+
+    // allocate caps
+    for (int i = 0; i < 5; i++) {
+        // get 4k block
+        struct capref mem;
+        err = ram_alloc(&mem, BASE_PAGE_BITS);
+        if (err_is_fail(err)) {
+            printf("ram_alloc: %s (%ld)\n", err_getstring(err), err);
+            return 1;
+        }
+
+        // get slot for retype dest
+        err = slot_alloc(&caps[i]);
+        if (err_is_fail(err)) {
+            printf("slot_alloc: %s (%ld)\n", err_getstring(err), err);
+            return 1;
+        }
+        // retype to selected type
+        err = cap_retype(caps[i], mem, types[i], BASE_PAGE_BITS);
+        if (err_is_fail(err)) {
+            printf("cap_retype: %s (%ld)\n", err_getstring(err), err);
+            return 1;
+        }
+
+        // cleanup source cap
+        printf("delete ram cap\n");
+        err = cap_destroy(mem);
+        if (err_is_fail(err)) {
+            printf("cap_delete(mem): %s (%ld)\n", err_getstring(err), err);
+            return 1;
+        }
+    }
+    // cap 6: 2M frame
+    size_t rb = 0;
+    err = frame_alloc(&caps[5], X86_64_LARGE_PAGE_SIZE, &rb);
+    if (err_is_fail(err) || rb != X86_64_LARGE_PAGE_SIZE) {
+        printf("frame_alloc: %s (%ld)\n", err_getstring(err), err);
+        return 1;
+    }
+    // cap 7: 1G frame
+    err = frame_alloc(&caps[6], X86_64_HUGE_PAGE_SIZE, &rb);
+    if (err_is_fail(err) || rb != X86_64_HUGE_PAGE_SIZE) {
+        printf("frame_alloc: %s (%ld)\n", err_getstring(err), err);
+        return 1;
+    }
+
+    paging_x86_64_flags_t attr = 0;
+    // select dest (ignore frame, asserts)
+    for (int i = 0; i < 4; i++) {
+        // select source
+        for (int j = 0; j < 7; j++) {
+            if (j >= 4) {
+                // frame
+                attr = FRAME_ACCESS_DEFAULT;
+            } else {
+                // ptable
+                attr = PTABLE_ACCESS_DEFAULT;
+            }
+            // try mapping
+            err = vnode_map(caps[i], caps[j], /*slot*/0, attr, /*off*/0, /*count*/1);
+            check_result(err, i, j);
+            // unmap if mapping succeeded
+            if (err_is_ok(err)) {
+                err = vnode_unmap(caps[i], caps[j], /*entry*/0, /*count*/1);
+                assert(err_is_ok(err));
+            }
+        }
+    }
+
+    printf("All tests executed: %d PASSED, %d FAILED\n", pass, fail);
+
+    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;
+}