static errval_t do_single_unmap(struct pmap_arm *pmap, genvaddr_t vaddr, size_t pte_count, bool delete_cap) { errval_t err; struct vnode *pt = find_ptable(pmap, vaddr); if (pt) { // 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, page->entry, page->u.frame.pte_count); if (err_is_fail(err)) { DEBUG_ERR(err, "vnode_unmap"); return err_push(err, LIB_ERR_VNODE_UNMAP); } // Free up the resources if (delete_cap) { err = cap_destroy(page->u.frame.cap); if (err_is_fail(err)) { return err_push(err, LIB_ERR_PMAP_DO_SINGLE_UNMAP); } } remove_vnode(pt, page); slab_free(&pmap->slab, page); } else { return LIB_ERR_PMAP_FIND_VNODE; } } 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; }
void remove_empty_vnodes(struct pmap_x86 *pmap, struct vnode *root, uint32_t entry, size_t len) { errval_t err; uint32_t end_entry = entry + len; for (struct vnode *n = root->u.vnode.children; n; n = n->next) { if (n->entry >= entry && n->entry < end_entry) { // sanity check and skip leaf entries if (!n->is_vnode) { continue; } // here we know that all vnodes we're interested in are // page tables assert(n->is_vnode); if (n->u.vnode.children) { remove_empty_vnodes(pmap, n, 0, PTABLE_SIZE); } // unmap err = vnode_unmap(root->u.vnode.cap, n->mapping); if (err_is_fail(err)) { debug_printf("remove_empty_vnodes: vnode_unmap: %s\n", err_getstring(err)); } // delete mapping cap first: underlying cap needs to exist for // this to work properly! err = cap_delete(n->mapping); if (err_is_fail(err)) { debug_printf("remove_empty_vnodes: cap_delete (mapping): %s\n", err_getstring(err)); } err = pmap->p.slot_alloc->free(pmap->p.slot_alloc, n->mapping); if (err_is_fail(err)) { debug_printf("remove_empty_vnodes: slot_free (mapping): %s\n", err_getstring(err)); } // delete capability err = cap_delete(n->u.vnode.cap); if (err_is_fail(err)) { debug_printf("remove_empty_vnodes: cap_delete (vnode): %s\n", err_getstring(err)); } if (!capcmp(n->u.vnode.cap, n->u.vnode.invokable)) { // invokable is always allocated in our cspace err = cap_destroy(n->u.vnode.invokable); if (err_is_fail(err)) { debug_printf("remove_empty_vnodes: cap_delete (vnode.invokable): %s\n", err_getstring(err)); } } err = pmap->p.slot_alloc->free(pmap->p.slot_alloc, n->u.vnode.cap); if (err_is_fail(err)) { debug_printf("remove_empty_vnodes: slot_free (vnode): %s\n", err_getstring(err)); } // remove vnode from list remove_vnode(root, n); slab_free(&pmap->slab, n); } } }