static errval_t do_single_map(struct pmap_arm *pmap, genvaddr_t vaddr, genvaddr_t vend, struct capref frame, size_t offset, size_t pte_count, vregion_flags_t flags) { // Get the page table struct vnode *ptable; errval_t err = get_ptable(pmap, vaddr, &ptable); 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); // XXX: reassess the following note -SG // NOTE: strictly speaking a l2 entry only has 8 bits, but due to the way // Barrelfish allocates l1 and l2 tables, we use 10 bits for the tracking // index here and in the map syscall uintptr_t index = ARM_USER_L2_OFFSET(vaddr); // Create user level datastructure for the mapping bool has_page = has_vnode(ptable, index, pte_count); assert(!has_page); struct vnode *page = slab_alloc(&pmap->slab); assert(page); page->is_vnode = false; page->entry = index; page->next = ptable->u.vnode.children; ptable->u.vnode.children = page; page->u.frame.cap = frame; page->u.frame.pte_count = pte_count; // Map entry into the page table err = vnode_map(ptable->u.vnode.cap, frame, index, pmap_flags, offset, pte_count); if (err_is_fail(err)) { return err_push(err, LIB_ERR_VNODE_MAP); } return SYS_ERR_OK; }
// this should work for x86_64 and x86_32. bool has_vnode(struct vnode *root, uint32_t entry, size_t len, bool only_pages) { assert(root != NULL); assert(root->is_vnode); struct vnode *n; uint32_t end_entry = entry + len; // region we check [entry .. end_entry) for (n = root->u.vnode.children; n; n = n->next) { // n is page table, we need to check if it's anywhere inside the // region to check [entry .. end_entry) // this amounts to n->entry == entry for len = 1 if (n->is_vnode && n->entry >= entry && n->entry < end_entry) { if (only_pages) { return has_vnode(n, 0, PTABLE_SIZE, true); } #ifdef LIBBARRELFISH_DEBUG_PMAP debug_printf("1: found page table inside our region\n"); #endif return true; } else if (n->is_vnode) { // all other vnodes do not overlap with us, so go to next assert(n->entry < entry || n->entry >= end_entry); continue; } // this remains the same regardless of `only_pages`. // n is frame [n->entry .. end) // 3 cases: // 1) entry < n->entry && end_entry >= end --> n is a strict subset of // our region // 2) entry inside n (entry >= n->entry && entry < end) // 3) end_entry inside n (end_entry >= n->entry && end_entry < end) uint32_t end = n->entry + n->u.frame.pte_count; if (entry < n->entry && end_entry >= end) { #ifdef LIBBARRELFISH_DEBUG_PMAP debug_printf("2: found a strict subset of our region: (%" PRIu32"--%"PRIu32") < (%"PRIu32"--%"PRIu32")\n", n->entry, end, entry, end_entry); #endif return true; } if (entry >= n->entry && entry < end) { #ifdef LIBBARRELFISH_DEBUG_PMAP debug_printf("3: found a region starting inside our region: (%" PRIu32"--%"PRIu32") <> (%"PRIu32"--%"PRIu32")\n", n->entry, end, entry, end_entry); #endif return true; } if (end_entry > n->entry && end_entry < end) { #ifdef LIBBARRELFISH_DEBUG_PMAP debug_printf("4: found a region ending inside our region: (%" PRIu32"--%"PRIu32") <> (%"PRIu32"--%"PRIu32")\n", n->entry, end, entry, end_entry); #endif return true; } } return false; }