/* Some more generic routines for helping with mapping */ void * sel4utils_dup_and_map(vka_t *vka, vspace_t *vspace, seL4_CPtr page, size_t size_bits) { int error; cspacepath_t page_path; cspacepath_t copy_path; void *mapping; /* First need to copy the cap */ error = vka_cspace_alloc_path(vka, ©_path); if (error != seL4_NoError) { return NULL; } vka_cspace_make_path(vka, page, &page_path); error = vka_cnode_copy(©_path, &page_path, seL4_AllRights); if (error != seL4_NoError) { vka_cspace_free(vka, copy_path.capPtr); return NULL; } /* Now map it in */ mapping = vspace_map_pages(vspace, ©_path.capPtr, NULL, seL4_AllRights, 1, size_bits, 1); if (!mapping) { vka_cnode_delete(©_path); vka_cspace_free(vka, copy_path.capPtr); return NULL; } return mapping; }
static void delete_iospace(env_t env, seL4_CPtr iospace) { cspacepath_t path; vka_cspace_make_path(&env->vka, iospace, &path); vka_cnode_delete(&path); }
int cnode_delete(env_t env, seL4_CPtr slot) { cspacepath_t path; vka_cspace_make_path(&env->vka, slot, &path); return vka_cnode_delete(&path); }
void sel4utils_unmap_dup(vka_t *vka, vspace_t *vspace, void *mapping, size_t size_bits) { /* Grap a copy of the cap */ seL4_CPtr copy = vspace_get_cap(vspace, mapping); cspacepath_t copy_path; assert(copy); /* now free the mapping */ vspace_unmap_pages(vspace, mapping, 1, size_bits, VSPACE_PRESERVE); /* delete and free the cap */ vka_cspace_make_path(vka, copy, ©_path); vka_cnode_delete(©_path); vka_cspace_free(vka, copy); }
void sel4utils_unmap_pages(vspace_t *vspace, void *vaddr, size_t num_pages, size_t size_bits, vka_t *vka) { uintptr_t v = (uintptr_t) vaddr; sel4utils_alloc_data_t *data = get_alloc_data(vspace); sel4utils_res_t *reserve = find_reserve(data, v); if (!sel4_valid_size_bits(size_bits)) { ZF_LOGE("Invalid size_bits %zu", size_bits); return; } if (vka == VSPACE_FREE) { vka = data->vka; } for (int i = 0; i < num_pages; i++) { seL4_CPtr cap = get_cap(data->top_level, v); /* unmap */ if (cap != 0) { int error = seL4_ARCH_Page_Unmap(cap); if (error != seL4_NoError) { ZF_LOGE("Failed to unmap page at vaddr %p", vaddr); } } if (vka) { cspacepath_t path; vka_cspace_make_path(vka, cap, &path); vka_cnode_delete(&path); vka_cspace_free(vka, cap); if (sel4utils_get_cookie(vspace, vaddr)) { vka_utspace_free(vka, kobject_get_type(KOBJECT_FRAME, size_bits), size_bits, sel4utils_get_cookie(vspace, vaddr)); } } if (reserve == NULL) { clear_entries(vspace, v, size_bits); } else { reserve_entries(vspace, v, size_bits); } assert(get_cap(data->top_level, v) != cap); assert(get_cookie(data->top_level, v) == 0); v += (1 << size_bits); vaddr = (void *) v; } }
static void _delete_node(allocman_t *alloc, struct utspace_split_node *node) { vka_cnode_delete(&node->ut); allocman_cspace_free(alloc, &node->ut); allocman_mspace_free(alloc, node, sizeof(*node)); }
static int _refill_pool(allocman_t *alloc, utspace_split_t *split, struct utspace_split_node **heads, size_t size_bits, uintptr_t paddr) { struct utspace_split_node *node; struct utspace_split_node *left, *right; int sel4_error; if (paddr == ALLOCMAN_NO_PADDR) { /* see if pool is actually empty */ if (heads[size_bits]) { return 0; } } else { /* see if the pool has the paddr we want */ for (node = heads[size_bits]; node; node = node->next) { if (node->paddr <= paddr && paddr < node->paddr + BIT(size_bits)) { return 0; } } } /* ensure we are not the highest pool */ if (size_bits >= sizeof(seL4_Word) * 8 - 2) { /* bugger, no untypeds bigger than us */ ZF_LOGV("Failed to refill pool of size %zu, no larger pools", size_bits); return 1; } /* get something from the highest pool */ if (_refill_pool(alloc, split, heads, size_bits + 1, paddr)) { /* could not fill higher pool */ ZF_LOGV("Failed to refill pool of size %zu", size_bits); return 1; } if (paddr == ALLOCMAN_NO_PADDR) { /* use the first node for lack of a better one */ node = heads[size_bits + 1]; } else { for (node = heads[size_bits + 1]; node && !(node->paddr <= paddr && paddr < node->paddr + BIT(size_bits + 1)); node = node->next); /* _refill_pool should not have returned if this wasn't possible */ assert(node); } /* allocate two new nodes */ left = _new_node(alloc); if (!left) { ZF_LOGV("Failed to allocate left node"); return 1; } right = _new_node(alloc); if (!right) { ZF_LOGV("Failed to allocate right node"); _delete_node(alloc, left); return 1; } /* perform the first retype */ sel4_error = seL4_Untyped_Retype(node->ut.capPtr, seL4_UntypedObject, size_bits, left->ut.root, left->ut.dest, left->ut.destDepth, left->ut.offset, 1); if (sel4_error != seL4_NoError) { _delete_node(alloc, left); _delete_node(alloc, right); /* Well this shouldn't happen */ ZF_LOGE("Failed to retype untyped, error %d\n", sel4_error); return 1; } /* perform the second retype */ sel4_error = seL4_Untyped_Retype(node->ut.capPtr, seL4_UntypedObject, size_bits, right->ut.root, right->ut.dest, right->ut.destDepth, right->ut.offset, 1); if (sel4_error != seL4_NoError) { vka_cnode_delete(&left->ut); _delete_node(alloc, left); _delete_node(alloc, right); /* Well this shouldn't happen */ ZF_LOGE("Failed to retype untyped, error %d\n", sel4_error); return 1; } /* all is done. remove the parent and insert the children */ _remove_node(&heads[size_bits + 1], node); left->parent = right->parent = node; left->sibling = right; left->origin_head = &heads[size_bits]; right->origin_head = &heads[size_bits]; right->sibling = left; if (node->paddr != ALLOCMAN_NO_PADDR) { left->paddr = node->paddr; right->paddr = node->paddr + BIT(size_bits); } else { left->paddr = right->paddr = ALLOCMAN_NO_PADDR; } /* insert in this order so that we end up pulling the untypeds off in order of contiugous * physical address. This makes various allocation problems slightly less likely to happen */ _insert_node(&heads[size_bits], right); _insert_node(&heads[size_bits], left); return 0; }
static int _refill_pool(allocman_t *alloc, utspace_split_t *split, uint32_t size_bits) { struct utspace_split_node *node; struct utspace_split_node *left, *right; int sel4_error; /* see if pool is actually empty */ if (split->heads[size_bits]) { return 0; } /* ensure we are not the highest pool */ if (size_bits >= 30) { /* bugger, no untypeds bigger than us */ return 1; } /* get something from the highest pool */ if (_refill_pool(alloc, split, size_bits + 1)) { /* could not fill higher pool */ return 1; } /* use the first node for lack of a better one */ node = split->heads[size_bits + 1]; /* allocate two new nodes */ left = _new_node(alloc); if (!left) { return 1; } right = _new_node(alloc); if (!right) { _delete_node(alloc, left); return 1; } /* perform the first retype */ #if defined(CONFIG_KERNEL_STABLE) sel4_error = seL4_Untyped_RetypeAtOffset(node->ut.capPtr, seL4_UntypedObject, 0, size_bits, left->ut.root, left->ut.dest, left->ut.destDepth, left->ut.offset, 1); #else sel4_error = seL4_Untyped_Retype(node->ut.capPtr, seL4_UntypedObject, size_bits, left->ut.root, left->ut.dest, left->ut.destDepth, left->ut.offset, 1); #endif if (sel4_error != seL4_NoError) { _delete_node(alloc, left); _delete_node(alloc, right); /* Well this shouldn't happen */ return 1; } /* perform the second retype */ #if defined(CONFIG_KERNEL_STABLE) sel4_error = seL4_Untyped_RetypeAtOffset(node->ut.capPtr, seL4_UntypedObject, BIT(size_bits), size_bits, right->ut.root, right->ut.dest, right->ut.destDepth, right->ut.offset, 1); #else sel4_error = seL4_Untyped_Retype(node->ut.capPtr, seL4_UntypedObject, size_bits, right->ut.root, right->ut.dest, right->ut.destDepth, right->ut.offset, 1); #endif if (sel4_error != seL4_NoError) { vka_cnode_delete(&left->ut); _delete_node(alloc, left); _delete_node(alloc, right); /* Well this shouldn't happen */ return 1; } /* all is done. remove the parent and insert the children */ _remove_node(&split->heads[size_bits + 1], node); left->parent = right->parent = node; left->sibling = right; right->sibling = left; if (node->paddr) { left->paddr = node->paddr; right->paddr = node->paddr + BIT(size_bits); } else { left->paddr = right->paddr = 0; } /* insert in this order so that we end up pulling the untypeds off in order of contiugous * physical address. This makes various allocation problems slightly less likely to happen */ _insert_node(&split->heads[size_bits], right); _insert_node(&split->heads[size_bits], left); return 0; }