32bit arm: fix large page support. Close T148.
authorSimon Gerber <simon.gerber@inf.ethz.ch>
Wed, 22 Jul 2015 13:06:31 +0000 (15:06 +0200)
committerDavid Cock <david.cock@inf.ethz.ch>
Tue, 11 Aug 2015 09:19:37 +0000 (11:19 +0200)
This implements a bit field to track the mapping of individual L2 tables for
armv5 and armv7 user space page table management. Having this tracking
bitfield we can use 1MB sections without having weird interference between
unused L2 tables and creating new section mappings.

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

include/arch/arm/barrelfish/invocations_arch.h
include/target/arm/barrelfish/pmap_target.h
kernel/arch/arm/syscall.c
kernel/arch/armv7/paging.c
lib/barrelfish/arch/arm/pmap_arch.c
lib/barrelfish/dispatch.c
lib/barrelfish/vspace/mmu_aware.c
usr/tests/large_page/Hakefile
usr/tests/large_page/malloc_test.c
usr/tests/large_page/map_test_32.c

index c77b40d..c0a84d8 100644 (file)
@@ -378,14 +378,14 @@ invoke_vnode_unmap(struct capref cap, capaddr_t mapping_cptr, int mapping_bits,
 
     pte_count -= 1;
 
-    assert(entry < 1024);
-    assert(pte_count < 1024);
+    assert(entry < 4096);
+    assert(pte_count < 4096);
     assert(mapping_bits <= 0xff);
 
     return syscall4((invoke_bits << 16) | (VNodeCmd_Unmap << 8) | SYSCALL_INVOKE,
                     invoke_cptr, mapping_cptr,
-                    ((mapping_bits & 0xff)<<20) | ((pte_count & 0x3ff)<<10) |
-                     (entry & 0x3ff)).error;
+                    ((mapping_bits & 0xff)<<24) | ((pte_count & 0xfff)<<12) |
+                     (entry & 0xfff)).error;
 }
 
 /**
index 36fc07d..794e785 100644 (file)
 
 #include <barrelfish/pmap.h>
 
+#define L2_PER_PAGE             4
+#define PTABLE_SIZE             (BASE_PAGE_SIZE / L2_PER_PAGE)
+#define L2_PAGE_IDX(idx)        ((idx) % L2_PER_PAGE)
+#define L2_PAGE_OFFSET(idx)     (L2_PAGE_IDX(idx) * PTABLE_SIZE)
+
+#define L2_IS_MAPPED(ptable, idx) \
+        ((ptable)->u.vnode.mapped & (1 << L2_PAGE_IDX(idx)))
+
+
 /// Node in the meta-data, corresponds to an actual VNode object
 struct vnode {
     uint16_t      entry;       ///< Page table entry of this VNode
@@ -24,15 +33,17 @@ struct vnode {
     struct vnode  *next;       ///< Next entry in list of siblings
     union {
         struct {
-            struct capref cap;         ///< Capability of this VNode
-            struct vnode  *children;   ///< Children of this VNode
+            struct capref cap[L2_PER_PAGE];     ///< Capability of this VNode
+            struct vnode  *children;            ///< Children of this VNode
+            uint8_t mapped;                     ///< which 1k tables are actually mapped
         } vnode; // for non-leaf node
         struct {
-            struct capref cap;         ///< Capability of this VNode
-            genvaddr_t    offset;      ///< Offset within mapped frame cap
-            vregion_flags_t flags;     ///< Flags for mapping
-            size_t        pte_count;   ///< number of mapped PTEs in this mapping
-        } frame; // for leaf node (maps page(s))
+            struct capref   cap;         ///< Capability of this VNode
+            genvaddr_t      offset;      ///< Offset within mapped frame cap
+            vregion_flags_t flags;       ///< Flags for mapping
+            uint16_t        pte_count;   ///< number of user page table entries consumed by this mapping
+            uint16_t        kernel_pte_count;   ///< number kernel ptes in this mapping
+        } frame; // for leaf node (maps page(s)/section(s))
     } u;
 };
 
index 596359f..432fd76 100644 (file)
@@ -346,10 +346,10 @@ handle_unmap(
 
     /* Retrieve arguments */
     capaddr_t  mapping_cptr  = (capaddr_t)sa->arg2;
-    int mapping_bits         = (((int)sa->arg3) >> 20) & 0xff;
-    size_t pte_count         = (((size_t)sa->arg3) >> 10) & 0x3ff;
+    int mapping_bits         = (((int)sa->arg3) >> 24) & 0xff;
+    size_t pte_count         = (((size_t)sa->arg3) >> 12) & 0xfff;
     pte_count               += 1;
-    size_t entry             = ((size_t)sa->arg3) & 0x3ff;
+    size_t entry             = ((size_t)sa->arg3) & 0xfff;
 
     errval_t err;
     struct cte *mapping = NULL;
index c28c5d9..80dad62 100644 (file)
@@ -67,27 +67,15 @@ caps_map_l1(struct capability* dest,
     //
     const int ARM_L1_SCALE = 4;
 
-    if (slot >= 1024) {
-        printf("slot = %"PRIuCSLOT"\n",slot);
-        panic("oops: slot id >= 1024");
-        return SYS_ERR_VNODE_SLOT_INVALID;
-    }
-
-    if (pte_count != 1) {
-        printf("pte_count = %zu\n",(size_t)pte_count);
-        panic("oops: pte_count");
-        return SYS_ERR_VM_MAP_SIZE;
-    }
-
     if (src->type != ObjType_VNode_ARM_l2) {
         //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)");
+        // ARM L1 has 4K entries, we need to fill in individual entries for
+        // 1M sections
+        // XXX: magic constant
+        if (slot >= 4096) {
+            panic("oops: slot >= 4096");
             return SYS_ERR_VNODE_SLOT_INVALID;
         }
 
@@ -97,14 +85,17 @@ caps_map_l1(struct capability* dest,
         }
 
         // check offset within frame
-        if ((offset + BYTES_PER_SECTION > get_size(src)) ||
+        if ((offset + pte_count * BYTES_PER_SECTION > get_size(src)) ||
             ((offset % BYTES_PER_SECTION) != 0)) {
+            printf("offset = %"PRIuPTR", pte_count=%"PRIuPTR
+                   ", src->size = %"PRIuGENSIZE", src->type = %d\n",
+                    offset, pte_count, get_size(src), src->type);
             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)) {
+        if (slot + pte_count > 4096) {
             return SYS_ERR_VM_MAP_SIZE;
         }
 
@@ -112,7 +103,7 @@ caps_map_l1(struct capability* dest,
         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;
+        union arm_l1_entry* entry = ((union arm_l1_entry*)dest_lvaddr) + slot;
         if (entry->invalid.type != L1_TYPE_INVALID_ENTRY) {
             panic("Remapping valid page.");
         }
@@ -136,7 +127,7 @@ caps_map_l1(struct capability* dest,
             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->section.base_address = (src_lpaddr + i * BYTES_PER_SECTION) >> 20;
 
             entry++;
 
@@ -147,35 +138,59 @@ caps_map_l1(struct capability* dest,
         // Flush TLB if remapping.
         cp15_invalidate_tlb();
         return SYS_ERR_OK;
-        return SYS_ERR_WRONG_MAPPING;
     }
 
-    if (slot >= ARM_L1_OFFSET(MEMORY_OFFSET) / ARM_L1_SCALE) {
+    // XXX: magic constant
+    if (slot >= 4096) {
+        printf("slot = %"PRIuCSLOT"\n",slot);
+        panic("oops: slot id >= 4096");
+        return SYS_ERR_VNODE_SLOT_INVALID;
+    }
+
+
+    // check offset within frame
+    if ((offset + pte_count * 1024 > get_size(src)) ||
+            ((offset % 1024) != 0)) {
+        printf("offset = %"PRIuPTR", pte_count=%"PRIuPTR
+                ", src->size = %"PRIuGENSIZE", src->type = %d\n",
+                offset, pte_count, get_size(src), src->type);
+        panic("oops: ptable offset invalid");
+        return SYS_ERR_FRAME_OFFSET_INVALID;
+    }
+
+    // check mapping does not overlap leaf page table
+    if (slot + pte_count > 4096) {
+        return SYS_ERR_VM_MAP_SIZE;
+    }
+
+
+    if (slot >= ARM_L1_OFFSET(MEMORY_OFFSET)) {
         printf("slot = %"PRIuCSLOT"\n",slot);
         panic("oops: slot id");
         return SYS_ERR_VNODE_SLOT_RESERVED;
     }
 
+    debug(SUBSYS_PAGING, "caps_map_l1: mapping %"PRIuPTR" L2 tables @%"PRIuCSLOT"\n",
+            pte_count, slot);
     // 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 * ARM_L1_SCALE);
+    union arm_l1_entry* entry = (union arm_l1_entry*)dest_lvaddr + slot;
 
     // Source
     genpaddr_t src_gpaddr = get_address(src);
-    lpaddr_t   src_lpaddr = gen_phys_to_local_phys(src_gpaddr);
+    lpaddr_t   src_lpaddr = gen_phys_to_local_phys(src_gpaddr) + offset;
 
-    assert(offset == 0);
     assert(aligned(src_lpaddr, 1u << 10));
     assert((src_lpaddr < dest_lpaddr) || (src_lpaddr >= dest_lpaddr + 16384));
 
     struct cte *src_cte = cte_for_cap(src);
     src_cte->mapping_info.pte_count = pte_count;
-    src_cte->mapping_info.pte = dest_lpaddr + (slot * ARM_L1_SCALE);
+    src_cte->mapping_info.pte = dest_lpaddr + slot;
     src_cte->mapping_info.offset = 0;
 
-    for (int i = 0; i < 4; i++, entry++)
+    for (int i = 0; i < pte_count; i++, entry++)
     {
         entry->raw = 0;
         entry->page_table.type   = L1_TYPE_PAGE_TABLE_ENTRY;
@@ -183,7 +198,7 @@ caps_map_l1(struct capability* dest,
         entry->page_table.base_address =
             (src_lpaddr + i * BASE_PAGE_SIZE / ARM_L1_SCALE) >> 10;
         debug(SUBSYS_PAGING, "L1 mapping %"PRIuCSLOT". @%p = %08"PRIx32"\n",
-              slot * ARM_L1_SCALE + i, entry, entry->raw);
+              slot + i, entry, entry->raw);
     }
 
     cp15_invalidate_tlb();
@@ -251,10 +266,10 @@ caps_map_l2(struct capability* dest,
         paging_set_flags(entry, kpi_paging_flags);
         entry->small_page.base_address = (src_lpaddr + i * BYTES_PER_PAGE) >> 12;
 
-        entry++;
-
         debug(SUBSYS_PAGING, "L2 mapping %08"PRIxLVADDR"[%"PRIuCSLOT"] @%p = %08"PRIx32"\n",
                dest_lvaddr, slot, entry, entry->raw);
+
+        entry++;
     }
 
     // Flush TLB if remapping.
@@ -307,7 +322,8 @@ size_t do_unmap(lvaddr_t pt, cslot_t slot, size_t num_pages)
     return unmapped_pages;
 }
 
-static inline void read_pt_entry(struct capability *pgtable, size_t slot, genpaddr_t *paddr)
+static inline void read_pt_entry(struct capability *pgtable,
+        size_t slot, bool is_section, genpaddr_t *paddr)
 {
     assert(type_is_vnode(pgtable->type));
     assert(paddr);
@@ -320,8 +336,13 @@ static inline void read_pt_entry(struct capability *pgtable, size_t slot, genpad
         case ObjType_VNode_ARM_l1:
         {
             union arm_l1_entry *e = (union arm_l1_entry*)lv;
-            *paddr = (genpaddr_t)(e->page_table.base_address) << 10;
-            return;
+            if (is_section) {
+                *paddr = (genpaddr_t)(e->section.base_address) << 20;
+                return;
+            } else {
+                *paddr = (genpaddr_t)(e->page_table.base_address) << 10;
+                return;
+            }
         }
         case ObjType_VNode_ARM_l2:
         {
@@ -339,10 +360,25 @@ errval_t page_mappings_unmap(struct capability *pgtable, struct cte *mapping, si
     assert(type_is_vnode(pgtable->type));
     //printf("page_mappings_unmap(%zd pages, slot = %zd)\n", num_pages, slot);
 
+    bool is_section = false;
+    if (pgtable->type == ObjType_VNode_ARM_l1) {
+        // transform slot to hw slot
+        if (mapping->cap.type == ObjType_VNode_ARM_l2) {
+            // l2 table
+            debug(SUBSYS_PAGING, "unmapping l2 tables: %zu, #pages: %zu\n",
+                    slot, num_pages);
+        }
+        else {
+            // section
+            is_section = true;
+            debug(SUBSYS_PAGING, "unmapping section: %zu, #pages: %zu\n",
+                    slot, num_pages);
+        }
+    }
     // get page table entry data
     genpaddr_t paddr;
     //lpaddr_t pte;
-    read_pt_entry(pgtable, slot, &paddr);
+    read_pt_entry(pgtable, slot, is_section, &paddr);
     lvaddr_t pt = local_phys_to_mem(gen_phys_to_local_phys(get_address(pgtable)));
 
     // get virtual address of first page
@@ -367,7 +403,8 @@ errval_t page_mappings_unmap(struct capability *pgtable, struct cte *mapping, si
     //printf("state before unmap: num_pages    = %zd\n", num_pages);
 
     if (num_pages != mapping->mapping_info.pte_count) {
-        printf("num_pages = %zu, mapping = %zu\n", num_pages, mapping->mapping_info.pte_count);
+        debug(SUBSYS_PAGING, "num_pages = %zu, mapping = %zu\n",
+                num_pages, mapping->mapping_info.pte_count);
         // want to unmap a different amount of pages than was mapped
         return SYS_ERR_VM_MAP_SIZE;
     }
@@ -414,17 +451,24 @@ void paging_dump_tables(struct dcb *dispatcher)
         // get level2 table
         union arm_l1_entry *l1_e = (union arm_l1_entry *)l1 + l1_index;
         if (!l1_e->raw) { continue; }
-        genpaddr_t ptable_gp = (genpaddr_t)(l1_e->page_table.base_address) << 10;
-        lvaddr_t ptable_lv = local_phys_to_mem(gen_phys_to_local_phys(ptable_gp));
-
-        for (int entry = 0; entry < ARM_L2_MAX_ENTRIES; entry++) {
-            union arm_l2_entry *e =
-                (union arm_l2_entry *)ptable_lv + entry;
-            genpaddr_t paddr = (genpaddr_t)(e->small_page.base_address) << BASE_PAGE_BITS;
-            if (!paddr) {
-                continue;
+        if (l1_e->invalid.type == 2) { // section 
+            genpaddr_t paddr = (genpaddr_t)(l1_e->section.base_address) << 20;
+            printf("%d: (section) 0x%"PRIxGENPADDR"\n", l1_index, paddr);
+        } else if (l1_e->invalid.type == 1) { // l2 table
+            genpaddr_t ptable_gp = (genpaddr_t)(l1_e->page_table.base_address) << 10;
+            lvaddr_t ptable_lv = local_phys_to_mem(gen_phys_to_local_phys(ptable_gp));
+
+            printf("%d: (l2table) 0x%"PRIxGENPADDR"\n", l1_index, ptable_gp);
+
+            for (int entry = 0; entry < ARM_L2_MAX_ENTRIES; entry++) {
+                union arm_l2_entry *e =
+                    (union arm_l2_entry *)ptable_lv + entry;
+                genpaddr_t paddr = (genpaddr_t)(e->small_page.base_address) << BASE_PAGE_BITS;
+                if (!paddr) {
+                    continue;
+                }
+                printf("%d.%d: 0x%"PRIxGENPADDR"\n", l1_index, entry, paddr);
             }
-            printf("%d.%d: 0x%"PRIxGENPADDR"\n", l1_index, entry, paddr);
         }
     }
 }
index 6ff2c38..f4f3359 100644 (file)
@@ -4,7 +4,7 @@
  */
 
 /*
- * Copyright (c) 2010-2013 ETH Zurich.
+ * Copyright (c) 2010-2015 ETH Zurich.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
 
 // Location of VSpace managed by this system.
 #ifdef __ARM_ARCH_7M__
-//virtual section 0x40000000-0x40100000 can not be used as regular memory 
+//virtual section 0x40000000-0x40100000 can not be used as regular memory
 //because of "bit-banding".
 //0x42000000-0x44000000 is also dangerous, so we start after that
-//XXX: there are more virtual regions we 
+//XXX: there are more virtual regions we
 //are not allowed to use -> find out where to reserve those
 #define VSPACE_BEGIN   ((lvaddr_t)(1UL*1024*1024*1024 + 64UL*1024*1024))    //0x44000000
 #else       //"normal" arm architectures
 #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)
 {
@@ -109,23 +104,162 @@ vregion_flags_to_kpi_paging_flags(vregion_flags_t flags)
     return (uintptr_t)flags;
 }
 
+// debug print preprocessor flag for this file
+//#define LIBBARRELFISH_DEBUG_PMAP
+
+/**
+ * \brief check whether region A = [start_a .. end_a) overlaps
+ * region B = [start_b .. end_b).
+ * \return true iff A overlaps B
+ */
+static bool is_overlapping(uint16_t start_a, uint16_t end_a, uint16_t start_b, uint16_t end_b)
+{
+    return
+        // B strict subset of A
+        (start_a < start_b && end_a >= end_b)
+        // start_a inside B
+        || (start_a >= start_b && start_a < end_b)
+        // end_a inside B
+        || (end_a > start_b && end_a < end_b);
+}
+
+/**
+ * \brief Check whether vnode `root' has entries in between [entry ..
+ * entry+len).
+ * \param root the vnode to look at
+ * \param entry first entry of the region to check
+ * \param len   length of the region to check
+ * \param only_pages true == do not report previously allocated lower-level
+ *                   page tables that are empty
+ * \return true iff entries exist in region.
+ */
+#if defined(LIBBARRELFISH_DEBUG_PMAP)
+#define DEBUG_HAS_VNODE
+#endif
+static 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;
+#ifdef DEBUG_HAS_VNODE
+    debug_printf("%s: checking region [%"PRIu32"--%"PRIu32"], only_pages = %d\n",
+            __FUNCTION__, entry, end_entry, only_pages);
+#endif
+
+    bool found_pages = false;
+    for (n = root->u.vnode.children; n; n = n->next) {
+        // region to check [entry .. end_entry)
+        if (n->is_vnode) {
+#ifdef DEBUG_HAS_VNODE
+            debug_printf("%s: looking at vnode: entry = %d, mapped = %"PRIx8"\n",
+                    __FUNCTION__, n->entry, n->u.vnode.mapped);
+#endif
+            // n is page table, we need to check if each mapped 1k L2 overlaps
+            // with the region to check [entry .. end_entry)
+            for (int i = 0; i < L2_PER_PAGE; i++) {
+                // ith 1k L2 is mapped
+#ifdef DEBUG_HAS_VNODE
+                debug_printf("%s: n->u.vnode.mapped & (1 << %d) == %d\n",
+                        __FUNCTION__, i, n->u.vnode.mapped & (1 << i));
+#endif
+                if (L2_IS_MAPPED(n, i)) {
+#ifdef DEBUG_HAS_VNODE
+                    debug_printf("%s: check overlapping: %"PRIu32"--%"PRIu32
+                            " <> %"PRIu32"--%"PRIu32"\n",
+                            __FUNCTION__, entry, end_entry,
+                            n->entry + i, n->entry + i + 1);
+#endif
+                    if (is_overlapping(entry, end_entry, n->entry + i, n->entry + i + 1)) {
+                        if (only_pages) {
+                            uint16_t rec_start = i * PTABLE_SIZE;
+#ifdef DEBUG_HAS_VNODE
+                            debug_printf("%s: checking recursively in %"PRIu16"--%"PRIu16"\n",
+                                    __FUNCTION__, rec_start, rec_start + PTABLE_SIZE);
+#endif
+                            found_pages = found_pages
+                                || has_vnode(n, rec_start, PTABLE_SIZE, true);
+                            if (found_pages) {
+                                return true;
+                            }
+                        } else {
+                            return true;
+                        }
+                    }
+                }
+            }
+        } else {
+            // not vnode
+            uint32_t end = n->entry + n->u.frame.pte_count;
+#ifdef DEBUG_HAS_VNODE
+            debug_printf("%s: looking at region: [%"PRIu32"--%"PRIu32"]\n",
+                    __FUNCTION__, n->entry, end);
+#endif
+
+            // do checks
+            if (is_overlapping(entry, end_entry, n->entry, end)) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
 /**
  * \brief Starting at a given root, return the vnode with entry equal to #entry
+ * \return vnode at index `entry` or NULL
  */
-static struct vnode *find_vnode(struct vnode *root, uint32_t entry)
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+#define DEBUG_FIND_VNODE
+#endif
+static struct vnode *find_vnode(struct vnode *root, uint16_t entry)
 {
     assert(root != NULL);
     assert(root->is_vnode);
     struct vnode *n;
 
+#ifdef DEBUG_FIND_VNODE
+    debug_printf("%s: looking for %"PRIu16"\n", __FUNCTION__, entry);
+#endif
+
     for(n = root->u.vnode.children; n != NULL; n = n->next) {
-        if(n->entry == entry) {
+        if (n->is_vnode &&
+            is_overlapping(entry, entry + 1, n->entry, n->entry + L2_PER_PAGE)) {
+#ifdef DEBUG_FIND_VNODE
+            debug_printf("%s: found ptable at [%"PRIu16"--%"PRIu16"]\n",
+                    __FUNCTION__, n->entry, n->entry + L2_PER_PAGE);
+#endif
+            return n;
+        }
+        else if (n->is_vnode) {
+            assert(!is_overlapping(entry, entry + 1, n->entry, n->entry + L2_PER_PAGE));
+            // ignore all other vnodes;
+            continue;
+        }
+
+        // not vnode
+        assert(!n->is_vnode);
+        uint16_t end = n->entry + n->u.frame.pte_count;
+#ifdef DEBUG_FIND_VNODE
+        debug_printf("%s: looking at section [%"PRIu16"--%"PRIu16"]\n", __FUNCTION__, n->entry, end);
+#endif
+        if (n->entry <= entry && entry < end) {
+#ifdef DEBUG_FIND_VNODE
+            debug_printf("%d \\in [%d, %d]\n", entry, n->entry, end);
+#endif
             return n;
         }
     }
     return NULL;
 }
 
+/**
+ * \brief check whether region [entry, entry+npages) is contained in a child
+ * of `root`.
+ */
 static bool inside_region(struct vnode *root, uint32_t entry, uint32_t npages)
 {
     assert(root != NULL);
@@ -145,31 +279,9 @@ static bool inside_region(struct vnode *root, uint32_t entry, uint32_t npages)
     return false;
 }
 
-static bool has_vnode(struct vnode *root, uint32_t entry, size_t len)
-{
-    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;
-}
-
+/**
+ * \brief remove vnode `item` from linked list of children of `root`
+ */
 static void remove_vnode(struct vnode *root, struct vnode *item)
 {
     assert(root->is_vnode);
@@ -188,7 +300,91 @@ static void remove_vnode(struct vnode *root, struct vnode *item)
         prev = walk;
         walk = walk->next;
     }
-    assert(!"Should not get here");
+    USER_PANIC("Should not get here");
+}
+
+static void unmap_l2_table(struct vnode *root, struct vnode *n, uint16_t e)
+{
+    errval_t err;
+    uint32_t entry = ROUND_DOWN(n->entry, L2_PER_PAGE) + e;
+    if (L2_IS_MAPPED(n, e)) {
+        err = vnode_unmap(root->u.vnode.cap[0], n->u.vnode.cap[e],
+                entry, 1);
+        if (err_is_fail(err)) {
+            debug_printf("remove_empty_vnodes: vnode_unmap: %s\n",
+                    err_getstring(err));
+            abort();
+        }
+
+        // delete capability, if not entry 0
+        if (e) {
+            err = cap_destroy(n->u.vnode.cap[e]);
+            if (err_is_fail(err)) {
+                debug_printf("remove_empty_vnodes: cap_destroy: %s\n",
+                        err_getstring(err));
+                abort();
+            }
+        }
+    }
+}
+
+/**
+ * \brief (recursively) remove empty page tables in region [entry ..
+ * entry+len) in vnode `root`.
+ */
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+#define DEBUG_REMOVE_EMPTY_VNODES
+#endif
+static void remove_empty_vnodes(struct slab_allocator *vnode_alloc, struct vnode *root,
+                         uint32_t entry, size_t len)
+{
+    // precondition: root does not have pages in [entry, entry+len)
+    assert(!has_vnode(root, entry, len, true));
+
+    errval_t err;
+    uint32_t end_entry = entry + len;
+    for (struct vnode *n = root->u.vnode.children; n; n = n->next) {
+        // 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 (entry < n->entry && end_entry >= n->entry + L2_PER_PAGE) {
+            // whole entry in region: completely unmap&free L2 page
+            for (int i = 0; i < L2_PER_PAGE; i++) {
+                unmap_l2_table(root, n, i);
+            }
+
+            // delete last copy of pt cap
+            err = cap_destroy(n->u.vnode.cap[0]);
+            assert(err_is_ok(err));
+
+            // remove vnode from list
+            remove_vnode(root, n);
+            slab_free(vnode_alloc, n);
+        } else if (entry >= n->entry && entry < n->entry + L2_PER_PAGE) {
+            // tail end of vnode in region:
+            uint16_t e = entry - n->entry;
+#ifdef DEBUG_REMOVE_EMPTY_VNODES
+            debug_printf("overlap: %"PRIu16" entries\n", e);
+#endif
+            for (; e < L2_PER_PAGE; e++) {
+                unmap_l2_table(root, n, e);
+            }
+        } else if (end_entry > n->entry && end_entry < n->entry + L2_PER_PAGE) {
+            // start of vnode in region
+            uint16_t e = end_entry - n->entry;
+#ifdef DEBUG_REMOVE_EMPTY_VNODES
+            debug_printf("overlap: %"PRIu16" entries\n", e);
+#endif
+            for (int i = 0; i < e; i++) {
+                unmap_l2_table(root, n, i);
+            }
+        }
+    }
 }
 
 /**
@@ -208,26 +404,24 @@ static errval_t alloc_vnode(struct pmap_arm *pmap_arm, struct vnode *root,
     newvnode->is_vnode = true;
 
     // The VNode capability
-    err = slot_alloc(&newvnode->u.vnode.cap);
+    err = slot_alloc(&newvnode->u.vnode.cap[0]);
     if (err_is_fail(err)) {
         return err_push(err, LIB_ERR_SLOT_ALLOC);
     }
 
-    err = vnode_create(newvnode->u.vnode.cap, type);
+    err = vnode_create(newvnode->u.vnode.cap[0], type);
     if (err_is_fail(err)) {
         return err_push(err, LIB_ERR_VNODE_CREATE);
     }
-
-    err = vnode_map(root->u.vnode.cap, newvnode->u.vnode.cap, entry,
-                    KPI_PAGING_FLAGS_READ | KPI_PAGING_FLAGS_WRITE, 0, 1);
-
-    if (err_is_fail(err)) {
-        return err_push(err, LIB_ERR_VNODE_MAP);
+    for (int i = 1; i < L2_PER_PAGE; i++) {
+        newvnode->u.vnode.cap[i] = NULL_CAP;
     }
 
     // The VNode meta data
-    newvnode->entry            = entry;
+    newvnode->entry            = ROUND_DOWN(entry, L2_PER_PAGE);
+    assert(newvnode->entry % L2_PER_PAGE == 0);
     newvnode->next             = root->u.vnode.children;
+    newvnode->u.vnode.mapped   = 0x0; // no entries mapped
     root->u.vnode.children     = newvnode;
     newvnode->u.vnode.children = NULL;
 
@@ -240,6 +434,9 @@ static errval_t alloc_vnode(struct pmap_arm *pmap_arm, struct vnode *root,
 /**
  * \brief Returns the vnode for the pagetable mapping a given vspace address
  */
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+#define DEBUG_GET_PTABLE
+#endif
 static errval_t get_ptable(struct pmap_arm  *pmap,
                            genvaddr_t        vaddr,
                            struct vnode    **ptable)
@@ -247,7 +444,8 @@ static errval_t get_ptable(struct pmap_arm  *pmap,
     // 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
     // idx here
-    uintptr_t idx = ARM_USER_L1_OFFSET(vaddr);
+    uintptr_t idx = ARM_L1_OFFSET(vaddr);
+    uintptr_t page_idx = L2_PAGE_IDX(idx);
     if ((*ptable = find_vnode(&pmap->root, idx)) == NULL)
     {
         // L1 table entries point to L2 tables so allocate an L2
@@ -255,6 +453,11 @@ static errval_t get_ptable(struct pmap_arm  *pmap,
 
         struct vnode *tmp = NULL; // Tmp variable for passing to alloc_vnode
 
+#ifdef DEBUG_GET_PTABLE
+        uintptr_t fidx = ROUND_DOWN(idx, L2_PER_PAGE);
+        debug_printf("allocating 4 x L2, entries = %"PRIuPTR"--%z"PRIuPTR"\n",
+                 fidx, fidx+4);
+#endif
         errval_t err = alloc_vnode(pmap, &pmap->root, ObjType_VNode_ARM_l2,
                                    idx, &tmp);
         if (err_is_fail(err)) {
@@ -264,11 +467,67 @@ static errval_t get_ptable(struct pmap_arm  *pmap,
         assert(tmp != NULL);
         *ptable = tmp; // Set argument to received value
 
-
         if (err_is_fail(err)) {
             return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
         }
     }
+    assert(ptable);
+    struct vnode *pt = *ptable;
+    if (!pt->is_vnode) {
+        debug_printf("found section @%d, trying to get ptable for %d\n",
+                pt->entry, idx);
+    }
+    assert(pt->is_vnode);
+#ifdef DEBUG_GET_PTABLE
+    debug_printf("have ptable: %p\n", pt);
+    debug_printf("mapped = %x\n", pt->u.vnode.mapped);
+    debug_printf("page_idx = %d\n", page_idx);
+    debug_printf("l2_is_mapped: %d\n", L2_IS_MAPPED(pt, page_idx));
+#endif
+    if (!L2_IS_MAPPED(pt, page_idx)) {
+#ifdef DEBUG_GET_PTABLE
+        debug_printf("need to map entry %d\n", page_idx);
+#endif
+        errval_t err;
+        uintptr_t offset = L2_PAGE_OFFSET(idx);
+#ifdef DEBUG_GET_PTABLE
+        debug_printf("mapping L1 entry %d at offset %"PRIuPTR"\n", idx, offset);
+#endif
+
+        // create copy of ptable cap for this index, if it doesn't exist
+        // already
+        if (capref_is_null(pt->u.vnode.cap[page_idx])) {
+#ifdef DEBUG_GET_PTABLE
+            debug_printf("allocating slot for chunk %d\n", page_idx);
+#endif
+            err = slot_alloc(&pt->u.vnode.cap[page_idx]);
+            if (err_is_fail(err)) {
+                return err_push(err, LIB_ERR_VNODE_MAP);
+            }
+
+#ifdef DEBUG_GET_PTABLE
+            debug_printf("creating copy for chunk %d\n", page_idx);
+#endif
+            err = cap_copy(pt->u.vnode.cap[page_idx], pt->u.vnode.cap[0]);
+            if (err_is_fail(err)) {
+                return err_push(err, LIB_ERR_VNODE_MAP);
+            }
+        }
+
+#ifdef DEBUG_GET_PTABLE
+            debug_printf("calling vnode_map() for chunk %d\n", page_idx);
+#endif
+        // map single 1k ptable
+        err = vnode_map(pmap->root.u.vnode.cap[0], pt->u.vnode.cap[page_idx], idx,
+                KPI_PAGING_FLAGS_READ | KPI_PAGING_FLAGS_WRITE, offset, 1);
+
+        if (err_is_fail(err)) {
+            return err_push(err, LIB_ERR_VNODE_MAP);
+        }
+
+        // set 1k ptable as mapped
+        pt->u.vnode.mapped |= 1 << page_idx;
+    }
 
     return SYS_ERR_OK;
 }
@@ -278,7 +537,7 @@ static struct vnode *find_ptable(struct pmap_arm  *pmap,
 {
     // NB Strictly there are 12 bits in the ARM L1, but allocations unit
     // of L2 is 1 page of L2 entries (4 tables) so
-    uintptr_t idx = ARM_USER_L1_OFFSET(vaddr);
+    uintptr_t idx = ARM_L1_OFFSET(vaddr);
     return find_vnode(&pmap->root, idx);
 }
 
@@ -290,41 +549,95 @@ static errval_t do_single_map(struct pmap_arm *pmap, genvaddr_t vaddr, genvaddr_
     // Get the page table
     struct vnode *ptable;
     uintptr_t entry;
-    if (flags&FLAGS_SECTION) {
+    bool is_large = false;
+
+    struct frame_identity fi;
+    err = invoke_frame_identify(frame, &fi);
+    if (err_is_fail(err)) {
+        return err_push(err, LIB_ERR_PMAP_FRAME_IDENTIFY);
+    }
+
+    if (flags & VREGION_FLAGS_LARGE &&
+        (vaddr & LARGE_PAGE_MASK) == 0 &&
+        fi.bits >= LARGE_PAGE_BITS &&
+        (fi.base & LARGE_PAGE_MASK) == 0) {
         //section mapping (1MB)
         //mapped in the L1 table at root
+        //
         ptable = &pmap->root;
-        entry = ARM_USER_L1_OFFSET(vaddr);
-        printf("do_single_map: large path\n");
+        entry = ARM_L1_OFFSET(vaddr);
+        is_large = true;
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+        printf("do_single_map: large path: entry=%zu\n", entry);
+#endif
     } else {
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+        debug_printf("%s: 4k path: mapping %"PRIxGENVADDR"\n", __FUNCTION__, vaddr);
+        debug_printf("4k path: L1 entry: %zu\n", ARM_USER_L1_OFFSET(vaddr));
+#endif
         //4k mapping
+        // XXX: reassess the following note -SG
+        // NOTE: strictly speaking a l2 entry only has 8 bits, while a l1 entry
+        // has 12 bits, but due to the way Barrelfish allocates l1 and l2 tables,
+        // we use 10 bits for the entry here and in the map syscall
         err = get_ptable(pmap, vaddr, &ptable);
+        if (err_is_fail(err)) {
+            DEBUG_ERR(err, "get_ptable() in do_single_map");
+            return err_push(err, LIB_ERR_PMAP_GET_PTABLE);
+        }
         entry = ARM_USER_L2_OFFSET(vaddr);
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+        debug_printf("%s: 4k path: L2 entry=%zu\n", __FUNCTION__, entry);
+        debug_printf("%s: ptable->is_vnode = %d\n",
+                __FUNCTION__, ptable->is_vnode);
+#endif
     }
-    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&~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
-    // idx here and in the map syscall
-    uintptr_t idx = ARM_USER_L2_OFFSET(vaddr);
+
+    // convert flags
+    flags &= ~(VREGION_FLAGS_LARGE | VREGION_FLAGS_HUGE);
+    uintptr_t pmap_flags = vregion_flags_to_kpi_paging_flags(flags);
+
+    uintptr_t user_pte_count = pte_count;
+    if (is_large) {
+        user_pte_count = DIVIDE_ROUND_UP(pte_count, L2_PER_PAGE);
+    }
+
+    // check if there is an overlapping mapping
+    if (has_vnode(ptable, entry, pte_count, false)) {
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+        debug_printf("has_vnode, only_pages=false  returned true\n");
+#endif
+        if (has_vnode(ptable, entry, pte_count, true)) {
+            printf("page already exists in 0x%"
+                    PRIxGENVADDR"--0x%"PRIxGENVADDR"\n", vaddr, vend);
+            return LIB_ERR_PMAP_EXISTING_MAPPING;
+        } else {
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+            debug_printf("has_vnode, only_pages=true  returned false, cleaning up empty ptables\n");
+#endif
+            // 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
+            // XXX: TODO: fix this + mapping of L2 to work on single 1k
+            // chunks
+            remove_empty_vnodes(&pmap->slab, ptable, entry, pte_count);
+        }
+    }
+
     // Create user level datastructure for the mapping
-    bool has_page = has_vnode(ptable, idx, pte_count);
-    assert(!has_page);
     struct vnode *page = slab_alloc(&pmap->slab);
     assert(page);
     page->is_vnode = false;
-    page->entry = idx;
+    page->entry = entry;
     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;
+    page->u.frame.pte_count = user_pte_count;
+    page->u.frame.kernel_pte_count = pte_count;
 
     // Map entry into the page table
-    err = vnode_map(ptable->u.vnode.cap, frame, idx,
+    err = vnode_map(ptable->u.vnode.cap[0], frame, entry,
                     pmap_flags, offset, pte_count);
     if (err_is_fail(err)) {
         return err_push(err, LIB_ERR_VNODE_MAP);
@@ -339,13 +652,26 @@ static errval_t do_map(struct pmap_arm *pmap, genvaddr_t vaddr,
     errval_t err;
     size_t page_size;
     size_t offset_level;
+
+    // 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);
+    }
+
     // determine mapping specific parts
-    if (flags&FLAGS_SECTION) {
+    if (flags & VREGION_FLAGS_LARGE &&
+        (vaddr & LARGE_PAGE_MASK) == 0 &&
+        fi.bits >= LARGE_PAGE_BITS &&
+        (fi.base & LARGE_PAGE_MASK) == 0) {
         //section mapping (1MB)
         page_size = LARGE_PAGE_SIZE;
         offset_level = ARM_L1_OFFSET(vaddr);
+#ifdef LIBBARRELFISH_DEBUG_PMAP
         printf("do_map: large path\n");
-        printf("page_size: %i, size: %i\n", page_size, size);
+        printf("page_size: %zx, size: %zx\n", page_size, size);
+#endif
     } else {
         //normal 4k mapping
         page_size = BASE_PAGE_SIZE;
@@ -354,11 +680,20 @@ static errval_t do_map(struct pmap_arm *pmap, genvaddr_t vaddr,
 
     size = ROUND_UP(size, page_size);
     size_t pte_count = DIVIDE_ROUND_UP(size, page_size);
+    if (flags & VREGION_FLAGS_LARGE) {
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+        printf("#pages: 0x%zu\n", pte_count);
+#endif
+    }
     genvaddr_t vend = vaddr + size;
 
+    if ((1UL << fi.bits) < size) {
+        return LIB_ERR_PMAP_FRAME_SIZE;
+    }
+
     //should be trivially true for section mappings
-    if ((ARM_L1_OFFSET(vaddr) == ARM_L1_OFFSET(vend-1)) ||
-        flags&FLAGS_SECTION) {
+    if ((ARM_L1_OFFSET(vaddr) == ARM_L1_OFFSET(vend)) ||
+        flags & VREGION_FLAGS_LARGE) {
         // fast path
         err = do_single_map(pmap, vaddr, vend, frame, offset, pte_count, flags);
         if (err_is_fail(err)) {
@@ -461,10 +796,9 @@ max_slabs_required(size_t bytes)
 }
 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;
+    // always need only one slab, as we can represent any size section mapping
+    // in a single struct vnode.
+    return 1;
 }
 
 /**
@@ -557,17 +891,31 @@ map(struct pmap     *pmap,
 {
     struct pmap_arm *pmap_arm = (struct pmap_arm *)pmap;
 
+    errval_t err;
     size_t base;
     size_t page_size;
     size_t slabs_required;
-    
+
+    struct frame_identity fi;
+    err = invoke_frame_identify(frame, &fi);
+    if (err_is_fail(err)) {
+        return err_push(err, LIB_ERR_PMAP_FRAME_IDENTIFY);
+    }
+
     // adjust the mapping to be on page boundaries
-    if (flags&FLAGS_SECTION) {
+    if (flags & VREGION_FLAGS_LARGE &&
+        (vaddr & LARGE_PAGE_MASK) == 0 &&
+        fi.bits >= LARGE_PAGE_BITS &&
+        (fi.base & LARGE_PAGE_MASK) == 0) {
         //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);
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+        size_t frame_sz = 1ULL<<fi.bits;
+        printf("map: large path, page_size: %i, base: %i, slabs: %i, size: %i,"
+                "frame size: %zu\n", page_size, base, slabs_required, size, frame_sz);
+#endif
     } else {
         //4k mapping
         base = BASE_PAGE_OFFSET(offset);
@@ -585,7 +933,7 @@ map(struct pmap     *pmap,
 
     if (slabs_required > slabs_free) {
         if (get_current_pmap() == pmap) {
-            errval_t err = refill_slabs(pmap_arm, slabs_required);
+            err = refill_slabs(pmap_arm, slabs_required);
             if (err_is_fail(err)) {
                 return err_push(err, LIB_ERR_SLAB_REFILL);
             }
@@ -610,11 +958,12 @@ static errval_t do_single_unmap(struct pmap_arm *pmap, genvaddr_t vaddr,
 {
     errval_t err;
     struct vnode *pt = find_ptable(pmap, vaddr);
-    if (pt) {
+    // pt->is_vnode == non-large mapping
+    if (pt && pt->is_vnode) {
         // analog to do_single_map we use 10 bits for tracking pages in user space -SG
         struct vnode *page = find_vnode(pt, ARM_USER_L2_OFFSET(vaddr));
         if (page && page->u.frame.pte_count == pte_count) {
-            err = vnode_unmap(pt->u.vnode.cap, page->u.frame.cap,
+            err = vnode_unmap(pt->u.vnode.cap[0], page->u.frame.cap,
                               page->entry, page->u.frame.pte_count);
             if (err_is_fail(err)) {
                 DEBUG_ERR(err, "vnode_unmap");
@@ -634,6 +983,22 @@ static errval_t do_single_unmap(struct pmap_arm *pmap, genvaddr_t vaddr,
         else {
             return LIB_ERR_PMAP_FIND_VNODE;
         }
+    } else if (pt) {
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+        debug_printf("section unmap: entry = %zu, pte_count = %zu\n",
+                pt->entry, pt->u.frame.kernel_pte_count);
+#endif
+        err = vnode_unmap(pmap->root.u.vnode.cap[0], pt->u.frame.cap,
+                          pt->entry, pt->u.frame.kernel_pte_count);
+        if (err_is_fail(err)) {
+            DEBUG_ERR(err, "vnode_unmap");
+            return err_push(err, LIB_ERR_VNODE_UNMAP);
+        }
+
+        remove_vnode(&pmap->root, pt);
+        slab_free(&pmap->slab, pt);
+    } else {
+        return LIB_ERR_PMAP_FIND_VNODE;
     }
 
     return SYS_ERR_OK;
@@ -719,23 +1084,31 @@ determine_addr(struct pmap   *pmap,
 {
     assert(pmap->vspace->head);
 
-    assert(alignment <= BASE_PAGE_SIZE); // NYI
+    if (alignment == 0) {
+        alignment = BASE_PAGE_SIZE;
+    } else {
+        alignment = ROUND_UP(alignment, BASE_PAGE_SIZE);
+    }
+    size_t size = ROUND_UP(memobj->size, alignment);
 
     struct vregion *walk = pmap->vspace->head;
     while (walk->next) { // Try to insert between existing mappings
         genvaddr_t walk_base = vregion_get_base_addr(walk);
-        genvaddr_t walk_size = vregion_get_size(walk);
+        genvaddr_t walk_size = ROUND_UP(vregion_get_size(walk), BASE_PAGE_SIZE);
+        genvaddr_t walk_end  = ROUND_UP(walk_base + walk_size, alignment);
         genvaddr_t next_base = vregion_get_base_addr(walk->next);
 
-        if (next_base > walk_base + walk_size + memobj->size &&
+        if (next_base > walk_end + size &&
             walk_base + walk_size > VSPACE_BEGIN) { // Ensure mappings are larger than VSPACE_BEGIN
-            *vaddr = walk_base + walk_size;
+            *vaddr = walk_end;
             return SYS_ERR_OK;
         }
         walk = walk->next;
     }
 
-    *vaddr = vregion_get_base_addr(walk) + vregion_get_size(walk);
+    *vaddr = ROUND_UP((vregion_get_base_addr(walk)
+                       + ROUND_UP(vregion_get_size(walk), alignment)),
+                       alignment);
     return SYS_ERR_OK;
 }
 
@@ -962,7 +1335,7 @@ pmap_init(struct pmap   *pmap,
               sizeof(pmap_arm->slab_buffer));
 
     pmap_arm->root.is_vnode         = true;
-    pmap_arm->root.u.vnode.cap      = vnode;
+    pmap_arm->root.u.vnode.cap[0]   = vnode;
     pmap_arm->root.next             = NULL;
     pmap_arm->root.u.vnode.children = NULL;
 
index 2dbf6c6..38c12cc 100644 (file)
@@ -344,6 +344,9 @@ void disp_pagefault(dispatcher_handle_t handle, lvaddr_t fault_address,
              DISP_NAME_LEN, disp->name, error, fault_address, ip);
     assert_print(str);
 
+    // dump hw page tables
+    debug_dump_hw_ptables();
+
 #if defined(__x86_64__) || defined(__i386__)
     snprintf(str, sizeof(str), "%s page fault due to %s%s, while in %s mode%s\n",
            error & ERR_PF_READ_WRITE ? "write" : "read",
index 273d529..0d10eac 100644 (file)
@@ -93,7 +93,7 @@ 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 alloc_size = ROUND_UP(req_size, BASE_PAGE_SIZE);
     size_t ret_size = 0;
 
     if (req_size > 0) {
index e5568d8..d9abc91 100644 (file)
                     },
  build application { target = "test_large_malloc",
                       cFiles = [ "malloc_test.c" ],
-                      architectures = [ "x86_64" ]
+                      architectures = allArchitectures
                     },
   build application { target = "test_large_mappings",
                       cFiles = [ "map_test_32.c" ],
-                      architectures = [ "x86_32" ]
+                      architectures = [ "x86_32", "armv7" ]
                     }
 
 ]
index 0bb1433..1f5f954 100644 (file)
@@ -25,14 +25,18 @@ int main(void)
     for (int k = 0; k < RUNS; k++) {
         // touch every 4k page in region
         bufs[k] = malloc(BUFSIZE);
+        if (!bufs[k]) {
+            debug_printf("malloc %d FAILED\n", k);
+            break;
+        }
         uint8_t *buf = bufs[k];
-        for (int i = 0; i < BUFSIZE / X86_64_BASE_PAGE_SIZE; i++) {
+        for (int i = 0; i < BUFSIZE / 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++) {
+        for (int i = 0; i < BUFSIZE / 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]);
index 5402cd1..c88babc 100644 (file)
@@ -21,7 +21,7 @@
 
 int main(void)
 {
-#if !defined(CONFIG_PSE)
+#if defined(__x86__) && !defined(CONFIG_PSE)
     debug_printf("PSE not enabled, change Config.hs and rebuild.\n");
     return 0;
 #endif