Added large page capabilities to the x86 architecture.
authorAndreas Dillier <dilliera@ethz.ch>
Mon, 25 Nov 2013 01:45:29 +0000 (02:45 +0100)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Thu, 30 Apr 2015 18:08:42 +0000 (20:08 +0200)
Signed-off-by: Simon Gerber <simon.gerber@inf.ethz.ch>

13 files changed:
hake/symbolic_targets.mk
include/arch/x86_64/barrelfish_kpi/paging_arch.h
include/barrelfish/pmap.h
include/target/x86_32/barrelfish_kpi/paging_target.h
include/target/x86_64/barrelfish_kpi/paging_target.h
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
lib/barrelfish/arch/arm/pmap_arch.c
lib/barrelfish/target/x86_32/pmap_target.c
lib/barrelfish/target/x86_64/pmap_target.c

index decd224..aa612ce 100644 (file)
@@ -171,6 +171,7 @@ MODULES_x86_64= \
        sbin/angler \
        sbin/sshd \
        sbin/lshw \
+       sbin/vnode_map_test \
 
 # the following are broken in the newidc system
 MODULES_x86_64_broken= \
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 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 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..0c4725d 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_64_BARRELFISH_KPI_PAGING_H
@@ -31,6 +31,12 @@ typedef uint64_t paging_x86_64_flags_t;
 #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                  0x20000000
+#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.
  */
index a539d16..0b7ebfc 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.
  */
 
 #include <kernel.h>
@@ -75,12 +75,12 @@ 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) { // disallow more than one page at a time
         return SYS_ERR_VM_MAP_SIZE;
     }
 
@@ -90,7 +90,79 @@ static errval_t x86_32_pdir(struct capability *dest, cslot_t slot,
     }
 #endif
 
+    //TODO large page code
+    size_t page_size = X86_32_LARGE_PAGE_SIZE;
+    if(dest->type == ObjType_VNode_x86_32_pdir &&
+       src->type != ObjType_VNode_x86_32_ptable)
+    {
+        printf("\tlarge page\n");
+        cslot_t last_slot = slot + pte_count;
+
+        if (src->type != ObjType_Frame &&
+            src->type != ObjType_DevFrame) { // Right mapping
+            printf("\tlarge page wrong mapping\n");
+            return SYS_ERR_WRONG_MAPPING;
+        }
+
+        // check offset within frame
+        if (offset + pte_count * page_size > get_size(src)) {
+            printf("\tlarge page wrong offset\n");
+            return SYS_ERR_FRAME_OFFSET_INVALID;
+        }
+
+        printf("calc new flags\n");
+        /* Calculate page access protection flags */
+        // Get frame cap rights
+        paging_x86_32_flags_t flags_large =
+            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;
+    
+        printf("calc addrs\n");
+        // Convert destination base address
+        genpaddr_t dest_gp   = get_address(dest);
+        lpaddr_t dest_lp     = gen_phys_to_local_phys(dest_gp);
+        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
+        printf("set metadata\n");
+        struct cte *src_cte = cte_for_cap(src);
+        src_cte->mapping_info.pte = dest_lp + slot * sizeof(union x86_32_ptable_entry);
+        src_cte->mapping_info.pte_count = pte_count;
+        src_cte->mapping_info.offset = offset;
+    
+
+        printf("start looping\n");
+        for (; slot < last_slot; slot++, offset += page_size) {
+            printf("looping\n");
+            union x86_32_ptable_entry *entry =
+                (union x86_32_ptable_entry *)dest_lv + slot;
+                
+            /* 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;
+            }
+            
+            printf("map it\n");
+            // Carry out the page mapping
+            paging_x86_32_map_large(entry, src_lp + offset, flags_large);
+        }
+
+        printf("mapping complete\n");
+        return SYS_ERR_OK;
+    }
+
     if (src->type != ObjType_VNode_x86_32_ptable) { // Right mapping
+        printf("error4\n");
         return SYS_ERR_WRONG_MAPPING;
     }
 
@@ -122,6 +194,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;
     }
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 da8fa7f..3bdcdfd 100644 (file)
@@ -4,12 +4,12 @@
  */
 
 /*
- * Copyright (c) 2007, 2008, 2009, 2010, 2011, 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>
@@ -119,9 +119,9 @@ errval_t startup_map_init(lvaddr_t vbase, lpaddr_t base, size_t size,
                     + X86_32_PDIR_BASE(vaddr) * X86_32_PTABLE_SIZE
                     + X86_32_PTABLE_BASE(vaddr)];
 
-        debug(SUBSYS_PAGING, "Mapping 4K page: vaddr = 0x%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 = %"PRIuLPADDR", PDIR_BASE = %"PRIuLPADDR", "
+              "PTABLE_BASE = %"PRIuLPADDR" -- ", 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 4b9b8c2..9cf12f3 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.
  */
 
 #include <kernel.h>
@@ -32,6 +32,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;
     }
@@ -47,6 +48,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
@@ -60,15 +62,50 @@ static errval_t x86_64_non_ptable(struct capability *dest, cslot_t slot,
         case ObjType_VNode_x86_64_pdpt:
             // TODO: huge page support, set page_size to HUGE_PAGE_SIZE
             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, set page_size to LARGE_PAGE_SIZE
             if (src->type != ObjType_VNode_x86_64_ptable) { // Right mapping
-                printf("src type invalid\n");
-                return SYS_ERR_WRONG_MAPPING;
+                printf("2m page ------\n");
+                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:
@@ -99,10 +136,20 @@ 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);
+        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;
@@ -113,7 +160,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;
     }
 
index 95dcf40..9aa7ea2 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
@@ -83,6 +83,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       :19;
         uint64_t        reserved2       :12;
@@ -161,6 +179,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
@@ -186,7 +234,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 94aedfe..9ded439 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.
  */
 
 /*
@@ -18,7 +18,7 @@
  * resource bootstrapping. The bootstrap ram allocator allocates pages.
  *
  *
- * The natural division of bits is 12/10/12, corresponding to 4K
+ * The natural division of bits is 12/8/12, corresponding to 4K
  * L1 entries in the L1 table and 256 L2 entries per L2
  * table. Unfortunately 256 entries consumes 1KB rather than a
  * page (4KB) so we pretend here and in the kernel caps page
@@ -84,6 +84,9 @@
 #define ARM_USER_L1_OFFSET(addr) ((uintptr_t)(addr >> 22) & 0x3ffu)
 #define ARM_USER_L2_OFFSET(addr) ((uintptr_t)(addr >> 12) & 0x3ffu)
 
+//flag for large page mapping
+#define FLAGS_LARGE 0x0100
+
 static inline uintptr_t
 vregion_flags_to_kpi_paging_flags(vregion_flags_t flags)
 {
@@ -267,6 +270,42 @@ static errval_t get_ptable(struct pmap_arm  *pmap,
 
     return SYS_ERR_OK;
 }
+/**
+ * \brief Returns the vnode for the TODO pdir mapping a given vspace address
+ */
+static errval_t get_pdir(struct pmap_arm  *pmap,
+                           genvaddr_t        vaddr,
+                           struct vnode    **ptable)
+{
+    // NB Strictly there are 12 bits in the ARM L1, but allocations unit
+    // of L2 is 1 page of L2 entries (4 tables) so we use 10 bits for the L1
+    // index here
+    uintptr_t index = ARM_USER_L1_OFFSET(vaddr);
+    if ((*ptable = find_vnode(&pmap->root, index)) == NULL)
+    {
+        // L1 table entries point to L2 tables so allocate an L2
+        // table for this L1 entry.
+
+        struct vnode *tmp = NULL; // Tmp variable for passing to alloc_vnode
+
+        errval_t err = alloc_vnode(pmap, &pmap->root, ObjType_VNode_ARM_l2,
+                                   index, &tmp);
+        if (err_is_fail(err)) {
+            DEBUG_ERR(err, "alloc_vnode");
+            return err;
+        }
+        assert(tmp != NULL);
+        *ptable = tmp; // Set argument to received value
+
+
+        if (err_is_fail(err)) {
+            return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
+        }
+    }
+
+    return SYS_ERR_OK;
+}
+
 
 static struct vnode *find_ptable(struct pmap_arm  *pmap,
                                  genvaddr_t vaddr)
@@ -283,7 +322,18 @@ static errval_t do_single_map(struct pmap_arm *pmap, genvaddr_t vaddr, genvaddr_
 {
     // Get the page table
     struct vnode *ptable;
-    errval_t err = get_ptable(pmap, vaddr, &ptable);
+    errval_t err;
+    if (flags&FLAGS_LARGE)
+    {
+        //large page mapping
+        err = get_pdir(pmap, vaddr, &ptable);
+        flags &= ~(FLAGS_LARGE);
+    }
+    else
+    {
+        //normal 4k mapping
+        err = get_ptable(pmap, vaddr, &ptable);
+    }
     if (err_is_fail(err)) {
         return err_push(err, LIB_ERR_PMAP_GET_PTABLE);
     }
@@ -319,9 +369,21 @@ static errval_t do_map(struct pmap_arm *pmap, genvaddr_t vaddr,
                        vregion_flags_t flags, size_t *retoff, size_t *retsize)
 {
     errval_t err;
+    
+    size_t page_size;
+    if (flags&FLAGS_LARGE)
+    {
+        //L2 mapping
+//        page_size = LARGE_PAGE_SIZE;
+    }
+    else
+    {
+        //normal 4k mapping
+        page_size = BASE_PAGE_SIZE;
+    }
+    size = ROUND_UP(size, page_size);
+    size_t pte_count = DIVIDE_ROUND_UP(size, page_size);
 
-    size = ROUND_UP(size, BASE_PAGE_SIZE);
-    size_t pte_count = DIVIDE_ROUND_UP(size, BASE_PAGE_SIZE);
     genvaddr_t vend = vaddr + size;
 
     if (ARM_L1_OFFSET(vaddr) == ARM_L1_OFFSET(vend-1)) {
@@ -334,7 +396,7 @@ static errval_t do_map(struct pmap_arm *pmap, genvaddr_t vaddr,
     } else { // multiple leaf page tables
         // first leaf
         uint32_t c = ARM_L2_MAX_ENTRIES - ARM_L2_OFFSET(vaddr);
-        genvaddr_t temp_end = vaddr + c * BASE_PAGE_SIZE;
+        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 +405,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 +428,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
@@ -516,10 +578,21 @@ 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);
-
+    if(flags&FLAGS_LARGE)
+    {
+        //large page mapping
+        //size += LARGE_PAGE_OFFSET(offset);
+        //size = ROUND_UP(size, LARGE_PAGE_SIZE);
+        //offset -= LARGE_PAGE_OFFSET(offset);
+    }
+    else
+    {
+        //4k mapping
+        size   += BASE_PAGE_OFFSET(offset);
+        size    = ROUND_UP(size, BASE_PAGE_SIZE);
+        offset -= BASE_PAGE_OFFSET(offset);
+    }
+    
     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;
index 158ef94..78fbd7d 100644 (file)
  */
 
 /*
- * Copyright (c) 2010, 2011, 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.
  */
 
 #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)
 
+//TODO better name/condition
+#define FLAGS_LARGE 0x0100
+#define FLAGS_UNMAP 0x01
+
 /**
  * \brief Translate generic vregion flags to architecture specific pmap flags
  */
@@ -67,6 +72,16 @@ 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;
@@ -232,6 +247,31 @@ static errval_t get_ptable(struct pmap_x86 *pmap, genvaddr_t base,
 
     return SYS_ERR_OK;
 }
+/**
+ * \brief Returns the vnode for the page directory mapping a given vspace address
+ */
+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);
+
+    // 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);
+        }
+    }
+#else
+    *pdir = &pmap->root;
+#endif
+
+    return SYS_ERR_OK;
+}
+
 
 static struct vnode *find_ptable(struct pmap_x86 *pmap, genvaddr_t base)
 {
@@ -256,18 +296,30 @@ static errval_t do_single_map(struct pmap_x86 *pmap, genvaddr_t vaddr, genvaddr_
                               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);
+    paging_x86_32_flags_t pmap_flags = vregion_to_pmap_flag(flags &~(FLAGS_LARGE));
 
-    // 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&FLAGS_LARGE) {
+        printf("pmap_single_map: large\n");
+        //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);
     }
-
+    
     // check if there is an overlapping mapping
-    if (has_vnode(ptable, X86_32_PTABLE_BASE(vaddr), pte_count)) {
+    if (has_vnode(ptable, base, pte_count)) {
         printf("page already exists in 0x%"PRIxGENVADDR"--0x%"PRIxGENVADDR"\n", vaddr, vend);
         return LIB_ERR_PMAP_EXISTING_MAPPING;
     }
@@ -276,7 +328,7 @@ static errval_t do_single_map(struct pmap_x86 *pmap, genvaddr_t vaddr, genvaddr_
     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 +337,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,12 +354,29 @@ 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);
+    size_t page_size;
+    size_t base;
+
+    if(flags&FLAGS_LARGE) {
+        printf("pmap_do_map: large\n");
+        //4M/2M (PAE) pages
+        page_size = X86_32_LARGE_PAGE_SIZE;
+        base = X86_32_PDIR_BASE(vaddr);
+        //printf("pmap_do_map: large: pte: %i\n", DIVIDE_ROUND_UP(size, page_size));
+        //printf("pmap_do_map: large: same_pdpt: %i\n", is_same_pdpt(vaddr, vaddr+size));
+    } else {
+        //4k mapping
+        page_size = X86_32_BASE_PAGE_SIZE;
+        base = X86_32_PTABLE_BASE(vaddr);
+    }
+
+    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) || (is_same_pdpt(vaddr, vend) && flags&FLAGS_LARGE)) {
         // fast path
+        //printf("pmap_do_map: fast path, pte_count: %i, %i\n", pte_count, DIVIDE_ROUND_UP(size, page_size));
         err = do_single_map(pmap, vaddr, vend, frame, offset, pte_count, flags);
         if (err_is_fail(err)) {
             return err_push(err, LIB_ERR_PMAP_DO_MAP);
@@ -314,8 +384,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 +395,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;
@@ -348,8 +418,14 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
         }
 
         // 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&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;
@@ -392,6 +468,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 +565,30 @@ 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)
+        printf("map: large path\n");
+        size   += X86_32_LARGE_PAGE_OFFSET(offset);
+        size    = ROUND_UP(size, X86_32_LARGE_PAGE_SIZE);
+        offset -= X86_32_LARGE_PAGE_OFFSET(offset);
+        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,7 +608,12 @@ static errval_t map(struct pmap *pmap, genvaddr_t vaddr, struct capref frame,
         }
     }
 
+    //printf("[map call do_map] vaddr = 0x%"PRIxGENVADDR", flag = %x\n", vaddr, (int)flags);
     err = do_map(x86, vaddr, frame, offset, size, flags, retoff, retsize);
+    if(flags&FLAGS_LARGE)
+    {
+        printf("map: large map complete\n");
+    }
     return err;
 }
 
@@ -772,8 +877,64 @@ 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_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 5314608..070d85d 100644 (file)
  */
 
 /*
- * Copyright (c) 2009, 2010, 2011, 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 <barrelfish/barrelfish.h>
 #define META_DATA_RESERVED_BASE (PML4_MAPPING_SIZE * (disp_get_core_id() + 1))
 #define META_DATA_RESERVED_SIZE (X86_64_BASE_PAGE_SIZE * 20000)
 
+//debug page_flag
+#define FLAGS_LARGE 0x0100
+#define FLAGS_HUGE  0x1000
+
 /**
  * \brief Translate generic vregion flags to architecture specific pmap flags
  */
@@ -64,6 +68,10 @@ 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);
 }
+static inline bool is_same_pdpt(genvaddr_t va1, genvaddr_t va2)
+{
+    return (va1>>X86_64_HUGE_PAGE_BITS) == (va2>>X86_64_HUGE_PAGE_BITS);
+}
 static inline genvaddr_t get_addr_prefix(genvaddr_t va)
 {
     return va >> X86_64_LARGE_PAGE_BITS;
@@ -176,7 +184,6 @@ static errval_t alloc_vnode(struct pmap_x86 *pmap, struct vnode *root,
     }
 
     // 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)) {
@@ -235,6 +242,64 @@ static errval_t get_ptable(struct pmap_x86 *pmap, genvaddr_t base,
     return SYS_ERR_OK;
 }
 
+/**
+ * \brief Returns the vnode for the pagedirectory (for large pages) mapping a given vspace address
+ *
+ */
+static errval_t get_pdir(struct pmap_x86 *pmap, genvaddr_t base,
+                            struct vnode **pdir)
+{
+    errval_t err;
+    struct vnode *root = &pmap->root;
+    struct vnode *pdpt;
+    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)) {
+            printf("failure mapping pml4\n");
+            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)) {
+            printf("failure mapping pdpt\n");
+            return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
+        }
+    }
+
+    return SYS_ERR_OK;
+}
+         
+/**
+ * \brief Returns the vnode for the pdpt (for huge pages) mapping a given vspace address
+ *
+ */
+static 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);
+
+    // 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 SYS_ERR_OK;
+}                   
+                            
 
 /**
  * \brief Returns the vnode for the pagetable mapping a given vspace address,
@@ -259,23 +324,71 @@ static struct vnode *find_ptable(struct pmap_x86 *pmap, genvaddr_t base)
     // PDIR mapping
     return find_vnode(pdir, X86_64_PDIR_BASE(base));
 }
+/**
+ * \brief Returns the vnode for the page directory mapping a given vspace address,
+ *     without performing allocations as get_pdir() does
+ */
+static struct vnode *find_pdir(struct pmap_x86 *pmap, genvaddr_t base)
+{
+    struct vnode *root = &pmap->root;
+    struct vnode *pdpt;
+    assert(root != NULL);
+
+    // PML4 mapping
+    if((pdpt = find_vnode(root, X86_64_PML4_BASE(base))) == NULL) {
+        return NULL;
+    }
+
+    // PDPT mapping
+    return find_vnode(pdpt, X86_64_PDPT_BASE(base));
+}
+/**
+ * \brief Returns the vnode for the page directory pointer table mapping 
+ *     for a given vspace address
+ */
+static struct vnode *find_pdpt(struct pmap_x86 *pmap, genvaddr_t base)
+{
+    struct vnode *root = &pmap->root;
+    assert(root != NULL);
+
+    // PDPT mapping
+    return find_vnode(root, X86_64_PML4_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,
                               vregion_flags_t flags)
 {
     // translate flags
-    paging_x86_64_flags_t pmap_flags = vregion_to_pmap_flag(flags);
+    paging_x86_64_flags_t pmap_flags = vregion_to_pmap_flag(flags & ~(FLAGS_LARGE | FLAGS_HUGE));
 
-    // 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;
+    //TODO meaningful condition
+    if(flags&FLAGS_LARGE) {
+        //large 2M pages, mapped into pdir
+        err = get_pdir(pmap, vaddr, &ptable);
+        table_base = X86_64_PDIR_BASE(vaddr);
+        printf("do_single_map: large, flags: %x\n", (unsigned int) flags);
+    } else if (flags&FLAGS_HUGE) {
+        //huge 1GB pages, mapped into pdpt
+        err = get_pdpt(pmap, vaddr, &ptable);
+        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);
     }
 
     // check if there is an overlapping mapping
-    if (has_vnode(ptable, X86_64_PTABLE_BASE(vaddr), pte_count)) {
+    if (has_vnode(ptable, table_base, pte_count)) {
         printf("page already exists in 0x%"PRIxGENVADDR"--0x%"PRIxGENVADDR"\n", vaddr, vend);
         return LIB_ERR_PMAP_EXISTING_MAPPING;
     }
@@ -284,7 +397,7 @@ static errval_t do_single_map(struct pmap_x86 *pmap, genvaddr_t vaddr, genvaddr_
     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 +406,12 @@ 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),
+    if (flags&FLAGS_LARGE)
+    {
+        printf("cap: --, frame: --, table_base: %lx, pmap_flags: %lx, offset: %lx, pte_count: %lx\n", (unsigned long) table_base, (unsigned long)pmap_flags, (unsigned long) offset, (unsigned long) pte_count);
+    }
+    
+    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,9 +429,29 @@ 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
+    size_t page_size;
+    size_t table_base;
+    // table_size same in x86_64
+    if (flags&FLAGS_LARGE) {
+        // large page branch (2MB)
+        page_size = X86_64_LARGE_PAGE_SIZE;
+        table_base = X86_64_PDIR_BASE(vaddr);
+        printf("do_map: large\n");
+    } else if (flags&FLAGS_HUGE) {
+        // huge page branch (1GB)
+        page_size = X86_64_HUGE_PAGE_SIZE;
+        table_base = X86_64_PDPT_BASE(vaddr);
+    } else {
+        // normal branch (4KB)
+        page_size = X86_64_BASE_PAGE_SIZE;
+        table_base = X86_64_PTABLE_BASE(vaddr);
+    }
+    size = ROUND_UP(size, page_size);
+    size_t pte_count = DIVIDE_ROUND_UP(size, page_size);
     genvaddr_t vend = vaddr + size;
+    //printf("\tpage_size: %i, size: %i, pte count: %i\n", (int)page_size, (int)size, (int)pte_count);
 
 #if 0
     struct frame_identity fi;
@@ -326,19 +464,23 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
             pte_count, (size_t)fi.bits);
 #endif
 
-
-    if (is_same_pdir(vaddr, vend)) {
+    // all mapping on one leaf table?
+    // trivially true for huge pages
+    if (is_same_pdir(vaddr, vend) || 
+        (is_same_pdpt(vaddr, vend) && flags&FLAGS_LARGE) ||
+        flags&FLAGS_HUGE) {
         // fast path
-        //debug_printf("do_map: fast path: %zd\n", pte_count);
+        //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;
+        //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);
@@ -348,8 +490,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_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,7 +506,7 @@ 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);
+            //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 (err_is_fail(err)) {
                 return err_push(err, LIB_ERR_PMAP_DO_MAP);
@@ -372,8 +514,17 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
         }
 
         // 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;
+
+        if (flags&FLAGS_LARGE) {
+            //large branch
+            c = X86_64_PDIR_BASE(vend) - X86_64_PDIR_BASE(temp_end);
+        } else {
+            //normal branch
+            c = X86_64_PTABLE_BASE(vend) - X86_64_PTABLE_BASE(temp_end);
+        }
+        
+        
         if (c) {
             // copy cap
             struct capref next;
@@ -414,6 +565,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
  *
@@ -501,15 +667,34 @@ static errval_t map(struct pmap *pmap, genvaddr_t vaddr, struct capref frame,
 {
     errval_t err;
     struct pmap_x86 *x86 = (struct pmap_x86*)pmap;
-
+    
+    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);
+    if (flags&FLAGS_LARGE) {
+        //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);
+        printf("map: large\n");
+    } else if (flags&FLAGS_HUGE) {
+        // 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) { 
         struct pmap *mypmap = get_current_pmap();
@@ -533,12 +718,44 @@ 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)
 {
     errval_t err;
+    bool large_flag = false;
+    bool huge_flag = false;
+    struct vnode *lpage = NULL;
+    //determine if we unmap a large page, find the page
+    if ((lpage = find_pdpt(pmap, vaddr)) != NULL) {
+        if ((lpage = find_vnode(lpage, X86_64_PML4_BASE(vaddr))) != NULL) {
+            huge_flag = lpage->u.frame.flags&FLAGS_HUGE;
+        }
+    }
+    if ((lpage = find_pdir(pmap, vaddr)) != NULL && !huge_flag) {
+        if ((lpage = find_vnode(lpage, X86_64_PDPT_BASE(vaddr))) != NULL) {
+            large_flag = lpage->u.frame.flags&FLAGS_LARGE;
+        }
+    }
+    
     struct vnode *pt = find_ptable(pmap, vaddr);
+
+    if (large_flag) {
+        pt = find_pdir(pmap, vaddr);
+    } else if (huge_flag) {
+        pt = find_pdpt(pmap, vaddr);
+    }
+
     if (pt) {
-        struct vnode *page = find_vnode(pt, X86_64_PTABLE_BASE(vaddr));
+        struct vnode *page;
+        if(large_flag) {
+            page = find_vnode(pt, X86_64_PDIR_BASE(vaddr));
+        } else if (huge_flag) {
+            page = find_vnode(pt, X86_64_PML4_BASE(vaddr));
+        } else {
+            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)) {
@@ -550,6 +767,7 @@ static errval_t do_single_unmap(struct pmap_x86 *pmap, genvaddr_t vaddr, size_t
             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);
                 }
             }
@@ -557,6 +775,7 @@ static errval_t do_single_unmap(struct pmap_x86 *pmap, genvaddr_t vaddr, size_t
             slab_free(&pmap->slab, page);
         }
         else {
+            printf("else, pmap find\n");
             return LIB_ERR_PMAP_FIND_VNODE;
         }
     }
@@ -578,40 +797,78 @@ 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;
+    bool large_flag = false;
+    bool huge_flag  = false;
+    //find table, then entry
+    if ((page = find_pdpt(x86, vaddr)) != NULL) {
+        if ((page = find_vnode(page, X86_64_PML4_BASE(vaddr))) != NULL) {
+            huge_flag = page->u.frame.flags&FLAGS_HUGE;
+        }
+    }
+    if ((page = find_pdir(x86, vaddr)) != NULL && !huge_flag) {
+        if ((page = find_vnode(page, X86_64_PDPT_BASE(vaddr))) != NULL) {
+            large_flag = page->u.frame.flags&FLAGS_LARGE;
+        }
+    }
+    size_t page_size = X86_64_BASE_PAGE_SIZE;
+    if (large_flag) {
+        //large 2M page
+        page_size = X86_64_LARGE_PAGE_SIZE;
+    } else if (huge_flag) {
+        //huge 1GB page
+        page_size = X86_64_HUGE_PAGE_SIZE;
+    }
+        
+    size = ROUND_UP(size, page_size);
     genvaddr_t vend = vaddr + size;
 
-    if (is_same_pdir(vaddr, vend)) {
+    if (is_same_pdir(vaddr, vend) || (is_same_pdpt(vaddr, vend)&&large_flag)
+        || huge_flag) {
         // fast path
-        err = do_single_unmap(x86, vaddr, size / X86_64_BASE_PAGE_SIZE, false);
+        err = do_single_unmap(x86, vaddr, size / page_size, false);
         if (err_is_fail(err)) {
+            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);
+        
+        if(large_flag) {
+            c = X86_64_PTABLE_SIZE - X86_64_PDIR_BASE(vaddr);
+        }
         err = do_single_unmap(x86, vaddr, c, false);
         if (err_is_fail(err)) {
+            printf("error first leaf\n");
             return err_push(err, LIB_ERR_PMAP_UNMAP);
         }
 
         // unmap full leaves
-        vaddr += c * X86_64_BASE_PAGE_SIZE;
+        vaddr += c * page_size;
         while (get_addr_prefix(vaddr) < get_addr_prefix(vend)) {
             c = X86_64_PTABLE_SIZE;
             err = do_single_unmap(x86, vaddr, X86_64_PTABLE_SIZE, true);
             if (err_is_fail(err)) {
+                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);
+
+        if (large_flag) {
+            c = X86_64_PDIR_BASE(vend) - X86_64_PDIR_BASE(vaddr);
+        }
         if (c) {
             err = do_single_unmap(x86, vaddr, c, true);
             if (err_is_fail(err)) {
+                printf("error remaining part\n");
                 return err_push(err, LIB_ERR_PMAP_UNMAP);
             }
         }
@@ -740,14 +997,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 +1038,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 +1081,57 @@ 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 < 1ul * 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);
+        debug_printf("first_free shifted: %"PRIuGENVADDR"\n", first_free<<39);
+        *retvaddr = first_free << 39;
+        printf("addr: %lx\n", *retvaddr);
+        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,