/** * \brief Allocates a new VNode, adding it to the page table and our metadata */ errval_t alloc_vnode(struct pmap_x86 *pmap, struct vnode *root, enum objtype type, uint32_t entry, struct vnode **retvnode) { errval_t err; struct vnode *newvnode = slab_alloc(&pmap->slab); if (newvnode == NULL) { return LIB_ERR_SLAB_ALLOC_FAIL; } // The VNode capability err = pmap->p.slot_alloc->alloc(pmap->p.slot_alloc, &newvnode->u.vnode.cap); if (err_is_fail(err)) { return err_push(err, LIB_ERR_SLOT_ALLOC); } err = vnode_create(newvnode->u.vnode.cap, type); if (err_is_fail(err)) { return err_push(err, LIB_ERR_VNODE_CREATE); } // XXX: need to make sure that vnode cap that we will invoke is in our cspace! if (get_croot_addr(newvnode->u.vnode.cap) != CPTR_ROOTCN) { // debug_printf("%s: creating vnode for another domain in that domain's cspace; need to copy vnode cap to our cspace to make it invokable\n", __FUNCTION__); err = slot_alloc(&newvnode->u.vnode.invokable); assert(err_is_ok(err)); err = cap_copy(newvnode->u.vnode.invokable, newvnode->u.vnode.cap); assert(err_is_ok(err)); } else { // debug_printf("vnode in our cspace: copying capref to invokable\n"); newvnode->u.vnode.invokable = newvnode->u.vnode.cap; } assert(!capref_is_null(newvnode->u.vnode.cap)); assert(!capref_is_null(newvnode->u.vnode.invokable)); err = pmap->p.slot_alloc->alloc(pmap->p.slot_alloc, &newvnode->mapping); if (err_is_fail(err)) { return err_push(err, LIB_ERR_SLOT_ALLOC); } // Map it err = vnode_map(root->u.vnode.invokable, newvnode->u.vnode.cap, entry, PTABLE_ACCESS_DEFAULT, 0, 1, newvnode->mapping); if (err_is_fail(err)) { return err_push(err, LIB_ERR_VNODE_MAP); } // The VNode meta data newvnode->is_vnode = true; newvnode->entry = entry; newvnode->next = root->u.vnode.children; root->u.vnode.children = newvnode; newvnode->u.vnode.children = NULL; *retvnode = newvnode; return SYS_ERR_OK; }
/** * \brief Allocates a new VNode, adding it to the page table and our metadata */ static errval_t alloc_vnode(struct pmap_arm *pmap_arm, struct vnode *root, enum objtype type, uint32_t entry, struct vnode **retvnode) { assert(root->is_vnode); errval_t err; struct vnode *newvnode = slab_alloc(&pmap_arm->slab); if (newvnode == NULL) { return LIB_ERR_SLAB_ALLOC_FAIL; } newvnode->is_vnode = true; // The VNode capability err = slot_alloc(&newvnode->u.vnode.cap); if (err_is_fail(err)) { return err_push(err, LIB_ERR_SLOT_ALLOC); } err = vnode_create(newvnode->u.vnode.cap, type); if (err_is_fail(err)) { return err_push(err, LIB_ERR_VNODE_CREATE); } 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); } // The VNode meta data newvnode->entry = entry; newvnode->next = root->u.vnode.children; root->u.vnode.children = newvnode; newvnode->u.vnode.children = NULL; if (retvnode) { *retvnode = newvnode; } return SYS_ERR_OK; }
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; }
int invalid_mappings(void) { // outline: // get pml4, pdpt, pdir, ptable, and frame // check all combinations to make sure that restrictions are implemented // correctly in kernel space // VALID: // map pdpt in pml4 // map pdir in pdpt // map pt in pdir // map frame in {pt, pdir, pdpt} // INVALID: // all other combinations errval_t err; struct capref caps[7]; struct capref mapping; // allocate slot for mapping cap: can reuse` err = slot_alloc(&mapping); if (err_is_fail(err)) { debug_printf("slot_alloc: %s (%ld)\n", err_getstring(err), err); return 1; } // allocate caps for (int i = 0; i < 5; i++) { // get 4k block struct capref mem; err = ram_alloc(&mem, BASE_PAGE_BITS); if (err_is_fail(err)) { debug_printf("ram_alloc: %s (%ld)\n", err_getstring(err), err); return 1; } // get slot for retype dest err = slot_alloc(&caps[i]); if (err_is_fail(err)) { debug_printf("slot_alloc: %s (%ld)\n", err_getstring(err), err); return 1; } // retype to selected type err = cap_retype(caps[i], mem, types[i], BASE_PAGE_BITS); if (err_is_fail(err)) { debug_printf("cap_retype: %s (%ld)\n", err_getstring(err), err); return 1; } // cleanup source cap DEBUG_INVALID_MAPPINGS("delete ram cap\n"); err = cap_destroy(mem); if (err_is_fail(err)) { debug_printf("cap_delete(mem): %s (%ld)\n", err_getstring(err), err); return 1; } } // cap 6: 2M frame size_t rb = 0; err = frame_alloc(&caps[5], X86_64_LARGE_PAGE_SIZE, &rb); if (err_is_fail(err) || rb != X86_64_LARGE_PAGE_SIZE) { debug_printf("frame_alloc: %s (%ld)\n", err_getstring(err), err); return 1; } // cap 7: 1G frame err = frame_alloc(&caps[6], X86_64_HUGE_PAGE_SIZE, &rb); if (err_is_fail(err) || rb != X86_64_HUGE_PAGE_SIZE) { debug_printf("frame_alloc: %s (%ld)\n", err_getstring(err), err); return 1; } paging_x86_64_flags_t attr = 0; // select dest (ignore frame, asserts) for (int i = 0; i < 4; i++) { // select source for (int j = 0; j < 7; j++) { if (j >= 4) { // frame attr = FRAME_ACCESS_DEFAULT; } else { // ptable attr = PTABLE_ACCESS_DEFAULT; } // try mapping err = vnode_map(caps[i], caps[j], /*slot*/0, attr, /*off*/0, /*count*/1, mapping); check_result(err, i, j); // unmap if mapping succeeded if (err_is_ok(err)) { err = vnode_unmap(caps[i], mapping); if (err_is_fail(err)) { DEBUG_ERR(err, "vnode_unmap"); } assert(err_is_ok(err)); // XXX: better API? err = cap_delete(mapping); assert(err_is_ok(err)); } } } printf("All tests executed: %d PASSED, %d FAILED\n", pass, fail); return 0; }