static errval_t do_single_modify_flags(struct pmap_arm *pmap, genvaddr_t vaddr, size_t pages, vregion_flags_t flags) { errval_t err = SYS_ERR_OK; struct vnode *ptable = find_ptable(pmap, vaddr); uint16_t ptentry = ARM_USER_L2_OFFSET(vaddr); if (ptable) { struct vnode *page = find_vnode(ptable, ptentry); if (page) { if (inside_region(ptable, ptentry, pages)) { // we're modifying part of a valid mapped region // arguments to invocation: invoke frame cap, first affected // page (as offset from first page in mapping), #affected // pages, new flags. Invocation should check compatibility of // new set of flags with cap permissions. size_t off = ptentry - page->entry; uintptr_t pmap_flags = vregion_flags_to_kpi_paging_flags(flags); err = invoke_frame_modify_flags(page->u.frame.cap, off, pages, pmap_flags); printf("invoke_frame_modify_flags returned error: %s (%"PRIuERRV")\n", err_getstring(err), err); return err; } else { // overlaps some region border return LIB_ERR_PMAP_EXISTING_MAPPING; } } } return SYS_ERR_OK; }
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; }
/** * \brief Returns the vnode for the pagetable mapping a given vspace address */ static errval_t get_ptable(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) { // 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 index = ARM_USER_L1_OFFSET(vaddr); return find_vnode(&pmap->root, index); }
vnode_t *get_vnode(uint32_t driver_num, uint32_t inode_num) { vnode_t *vnode = find_vnode(driver_num, inode_num); if(!vnode) { vnode = get_free_vnode(); vfs_msg_getnode *getnode_msg = (vfs_msg_getnode *)calloc(sizeof(vfs_msg_getnode)); getnode_msg->msg_type = VFSM_GETNODE; getnode_msg->node.driver_num = driver_num; getnode_msg->node.inode_num = inode_num; send2(driver_num, getnode_msg); free(getnode_msg); getnode_msg = waitmsg(driver_num,0); if(getnode_msg->node.driver_num) { memcopy((uint8_t *)vnode, (uint8_t *)&getnode_msg->node, sizeof(vnode_t)); } else { _syscall_printf("\nGetnode failed!",0); } free(getnode_msg); } return vnode; }