static struct utspace_split_node *_new_node(allocman_t *alloc) { int error; struct utspace_split_node *node; node = (struct utspace_split_node*) allocman_mspace_alloc(alloc, sizeof(*node), &error); if (error) { ZF_LOGV("Failed to allocate node of size %zu", sizeof(*node)); return NULL; } error = allocman_cspace_alloc(alloc, &node->ut); if (error) { allocman_mspace_free(alloc, node, sizeof(*node)); ZF_LOGV("Failed to allocate slot"); return NULL; } return node; }
int main(int argc, char *argv[]) { (void)argc; (void)argv; /* Current log level is set to ZF_LOG_INFO by defining ZF_LOG_LEVEL * before zf_log.h include. All log messages below INFO level will be * compiled out. */ ZF_LOGV("Argument of this VERBOSE message will not be evaluated: %i", call_exit()); ZF_LOGI("So you will see that INFO message"); /* Output log level is set to WARN and then to INFO. Argument of INFO log * statement will be evaluated only once (after setting output log level to * INFO). */ zf_log_set_output_level(ZF_LOG_WARN); int count = 0; for (int i = 2; 0 < i--;) { ZF_LOGI("Argument of this INFO message will be evaluated only once: %i", ++count); zf_log_set_output_level(ZF_LOG_INFO); } if (1 != count) { abort(); } ZF_LOGI("And you will see that INFO message"); return 0; }
static int _insert_new_node(allocman_t *alloc, struct utspace_split_node **head, cspacepath_t ut, uintptr_t paddr) { int error; struct utspace_split_node *node; node = (struct utspace_split_node*) allocman_mspace_alloc(alloc, sizeof(*node), &error); if (error) { ZF_LOGV("Failed to allocate node of size %zu", sizeof(*node)); return 1; } node->parent = NULL; node->ut = ut; node->paddr = paddr; node->origin_head = head; _insert_node(head, node); return 0; }
int test_timer(driver_env_t env) { int error = ltimer_set_timeout(&env->timer.ltimer, 1 * NS_IN_S, TIMEOUT_PERIODIC); test_assert_fatal(!error); for (int i = 0; i < 3; i++) { wait_for_timer_interrupt(env); ZF_LOGV("Tick\n"); } error = ltimer_reset(&env->timer.ltimer); test_assert_fatal(!error); return sel4test_get_result(); }
int test_gettime_timeout(driver_env_t env) { int error = 0; uint64_t start, end; start = timestamp(env); error = ltimer_set_timeout(&env->timer.ltimer, 1 * NS_IN_MS, TIMEOUT_PERIODIC); test_assert_fatal(!error); for (int i = 0; i < 3; i++) { wait_for_timer_interrupt(env); ZF_LOGV("Tick\n"); } end = timestamp(env); test_gt(end, start); error = ltimer_reset(&env->timer.ltimer); test_assert_fatal(!error); return sel4test_get_result(); }
seL4_Word _utspace_split_alloc(allocman_t *alloc, void *_split, size_t size_bits, seL4_Word type, const cspacepath_t *slot, uintptr_t paddr, bool canBeDev, int *error) { utspace_split_t *split = (utspace_split_t*)_split; size_t sel4_size_bits; int sel4_error; struct utspace_split_node *node; /* get size of untyped call */ sel4_size_bits = get_sel4_object_size(type, size_bits); if (size_bits != vka_get_object_size(type, sel4_size_bits) || size_bits == 0) { SET_ERROR(error, 1); return 0; } struct utspace_split_node **head = NULL; /* if we're allocating at a particular paddr then we will just trawl through every pool * and see if we can find out which one has what we want */ if (paddr != ALLOCMAN_NO_PADDR) { if (canBeDev) { head = find_head_for_paddr(split->dev_heads, paddr, size_bits); if (!head) { head = find_head_for_paddr(split->dev_mem_heads, paddr, size_bits); } } if (!head) { head = find_head_for_paddr(split->heads, paddr, size_bits); } if (!head) { SET_ERROR(error, 1); ZF_LOGE("Failed to find any untyped capable of creating an object at address %p", (void*)paddr); return 0; } if (_refill_pool(alloc, split, head, size_bits, paddr)) { /* out of memory? */ SET_ERROR(error, 1); ZF_LOGV("Failed to refill pool to allocate object of size %zu", size_bits); return 0; } /* search for the node we want to use. We have the advantage of knowing that * due to objects being size aligned that the base paddr of the untyped will * be exactly the paddr we want */ for (node = head[size_bits]; node && node->paddr != paddr; node = node->next); /* _refill_pool should not have returned if this wasn't possible */ assert(node); } else { /* if we can use device memory then preference allocating from there */ if (canBeDev) { if (_refill_pool(alloc, split, split->dev_mem_heads, size_bits, ALLOCMAN_NO_PADDR)) { /* out of memory? */ SET_ERROR(error, 1); ZF_LOGV("Failed to refill pool to allocate object of size %zu", size_bits); return 0; } head = split->dev_mem_heads; } if (!head) { head = split->heads; if (_refill_pool(alloc, split, head, size_bits, ALLOCMAN_NO_PADDR)) { /* out of memory? */ SET_ERROR(error, 1); ZF_LOGV("Failed to refill pool to allocate object of size %zu", size_bits); return 0; } } /* use the first node for lack of a better one */ node = head[size_bits]; } /* Perform the untyped retype */ sel4_error = seL4_Untyped_Retype(node->ut.capPtr, type, sel4_size_bits, slot->root, slot->dest, slot->destDepth, slot->offset, 1); if (sel4_error != seL4_NoError) { /* Well this shouldn't happen */ ZF_LOGE("Failed to retype untyped, error %d\n", sel4_error); SET_ERROR(error, 1); return 0; } /* remove the node */ _remove_node(&head[size_bits], node); SET_ERROR(error, 0); /* return the node as a cookie */ return (seL4_Word)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; }