diff --git a/conts/libl4thread/include/l4thread/addr.h b/conts/libl4thread/include/l4thread/addr.h index e7b4519..8182ec0 100644 --- a/conts/libl4thread/include/l4thread/addr.h +++ b/conts/libl4thread/include/l4thread/addr.h @@ -1,5 +1,5 @@ /* - * Address allocation pool + * Address allocation pool. * * Copyright (C) 2007 Bahadir Balban */ @@ -21,7 +21,7 @@ int address_pool_init_with_idpool(struct address_pool *pool, int address_pool_init(struct address_pool *pool, unsigned long start, unsigned long end, int size); -void *address_new(struct address_pool *pool, int npages); -int address_del(struct address_pool *, void *addr, int npages); +void *address_new(struct address_pool *pool, int nitems, int size); +int address_del(struct address_pool *, void *addr, int nitems, int size); #endif /* __ADDR_H__ */ diff --git a/conts/libl4thread/include/l4thread/stack.h b/conts/libl4thread/include/l4thread/stack.h new file mode 100644 index 0000000..d0e5f09 --- /dev/null +++ b/conts/libl4thread/include/l4thread/stack.h @@ -0,0 +1,19 @@ +/* + * Stack space helper routines. + * + * Copyright (C) 2009 B Labs Ltd. + */ +#ifndef __LIB_STACK_H__ +#define __LIB_STACK_H__ + +/* Checks if l4_set_stack_params is called. */ +#define IS_STACK_SETUP() (lib_stack_size) + +int stack_pool_init(unsigned long stack_start, + unsigned long stack_end, + unsigned long stack_size); + +void *get_stack_space(void); +int delete_stack_space(void *stack_address); + +#endif /* __LIB_STACK_H__ */ diff --git a/conts/libl4thread/include/l4thread/tcb.h b/conts/libl4thread/include/l4thread/tcb.h index 1c81111..da332e0 100644 --- a/conts/libl4thread/include/l4thread/tcb.h +++ b/conts/libl4thread/include/l4thread/tcb.h @@ -14,22 +14,30 @@ struct utcb_head { }; /* A simple thread control block for the thread library. */ -struct l4t_tcb { +struct tcb { + /* Task list */ struct link list; + + /* Task id */ int tid; + + /* Chain of utcb descriptors */ struct utcb_head *utcb_head; + + /* Stack and utcb address */ unsigned long utcb_addr; + unsigned long stack_addr; }; -/* This struct keeps track of all the threads handled by the thread lib. */ -struct l4t_global_list { +/* All the threads handled by the thread lib are kept in this list. */ +struct global_list { int total; struct link list; }; -struct l4t_tcb *l4t_find_task(int tid); -struct l4t_tcb *l4t_tcb_alloc_init(struct l4t_tcb *parent, unsigned int flags); -void l4t_global_add_task(struct l4t_tcb *task); -void l4t_global_remove_task(struct l4t_tcb *task); +struct tcb *find_task(int tid); +struct tcb *tcb_alloc_init(struct tcb *parent, unsigned int flags); +void global_add_task(struct tcb *task); +void global_remove_task(struct tcb *task); #endif /* __LIB_TCB_H__ */ diff --git a/conts/libl4thread/include/l4thread/thread.h b/conts/libl4thread/include/l4thread/thread.h index 319233e..8cd3125 100644 --- a/conts/libl4thread/include/l4thread/thread.h +++ b/conts/libl4thread/include/l4thread/thread.h @@ -6,13 +6,13 @@ #ifndef __LIB_THREAD_H__ #define __LIB_THREAD_H__ -int set_stack_params(unsigned long stack_top, +int l4_set_stack_params(unsigned long stack_top, unsigned long stack_bottom, unsigned long stack_size); -int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end); +int l4_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end); -int l4thread_create(struct task_ids *ids, unsigned int flags, +int l4_thread_create(struct task_ids *ids, unsigned int flags, int (*func)(void *), void *arg); -void l4thread_kill(struct task_ids *ids); +void l4_thread_exit(int retval); #endif /* __LIB_THREAD_H__ */ diff --git a/conts/libl4thread/include/l4thread/utcb-common.h b/conts/libl4thread/include/l4thread/utcb-common.h index e5f5fef..47d71f8 100644 --- a/conts/libl4thread/include/l4thread/utcb-common.h +++ b/conts/libl4thread/include/l4thread/utcb-common.h @@ -1,5 +1,5 @@ /* - * UTCB handling common helper routines + * UTCB handling common helper routines. * * Copyright (C) 2009 B Labs Ltd. */ diff --git a/conts/libl4thread/include/l4thread/utcb.h b/conts/libl4thread/include/l4thread/utcb.h index f16f310..086aa93 100644 --- a/conts/libl4thread/include/l4thread/utcb.h +++ b/conts/libl4thread/include/l4thread/utcb.h @@ -1,5 +1,5 @@ /* - * UTCB handling helper routines + * UTCB handling helper routines. * * Copyright (C) 2009 B Labs Ltd. */ @@ -8,7 +8,10 @@ #include -unsigned long get_utcb_addr(struct l4t_tcb *task); -int delete_utcb_addr(struct l4t_tcb *task); +/* Checks if l4_set_stack_params is called. */ +#define IS_UTCB_SETUP() (lib_utcb_range_size) + +unsigned long get_utcb_addr(struct tcb *task); +int delete_utcb_addr(struct tcb *task); #endif /* __LIB_UTCB_H__ */ diff --git a/conts/libl4thread/src/addr.c b/conts/libl4thread/src/addr.c index 90c67dd..7318aca 100644 --- a/conts/libl4thread/src/addr.c +++ b/conts/libl4thread/src/addr.c @@ -33,21 +33,21 @@ int address_pool_init(struct address_pool *pool, return 0; } -void *address_new(struct address_pool *pool, int npages) +void *address_new(struct address_pool *pool, int nitems, int size) { - unsigned int pfn; + unsigned int idx; - if ((int)(pfn = ids_new_contiguous(pool->idpool, npages)) < 0) + if ((int)(idx = ids_new_contiguous(pool->idpool, nitems)) < 0) return 0; - return (void *)__pfn_to_addr(pfn) + pool->start; + return (void *)(idx * size) + pool->start; } -int address_del(struct address_pool *pool, void *addr, int npages) +int address_del(struct address_pool *pool, void *addr, int nitems, int size) { - unsigned long pfn = __pfn(page_align(addr) - pool->start); + unsigned long idx = (addr - (void *)pool->start) / size; - if (ids_del_contiguous(pool->idpool, pfn, npages) < 0) { + if (ids_del_contiguous(pool->idpool, idx, nitems) < 0) { printf("%s: Invalid address range returned to " "virtual address pool.\n", __FUNCTION__); return -1; diff --git a/conts/libl4thread/src/arch-arm/new_thread.S b/conts/libl4thread/src/arch-arm/new_thread.S new file mode 100644 index 0000000..1014817 --- /dev/null +++ b/conts/libl4thread/src/arch-arm/new_thread.S @@ -0,0 +1,12 @@ +#include + + +BEGIN_PROC(setup_new_thread) + ldr r0, [sp], #-4 @ Load first argument + mov lr, pc @ Save return address + ldr pc, [sp], #-4 @ Load function pointer from stack + b l4_thread_exit @ Call l4_thread_exit for cleanup +new_thread_exit: + b new_thread_exit @ Never reaches here +END_PROC(setup_new_thread) + diff --git a/conts/libl4thread/src/idpool.c b/conts/libl4thread/src/idpool.c new file mode 100644 index 0000000..17fd450 --- /dev/null +++ b/conts/libl4thread/src/idpool.c @@ -0,0 +1,87 @@ +/* + * Used for thread and space ids, and also for + * utcb tracking in page-sized-chunks. + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include +#include +#include + +struct id_pool *id_pool_new_init(int totalbits) +{ + int nwords = BITWISE_GETWORD(totalbits) + 1; + struct id_pool *new = kzalloc((nwords * SZ_WORD) + + sizeof(struct id_pool)); + if (!new) + return PTR_ERR(-ENOMEM); + + new->nwords = nwords; + new->bitlimit = totalbits; + + return new; +} + +/* Search for a free slot up to the limit given */ +int id_new(struct id_pool *pool) +{ + return find_and_set_first_free_bit(pool->bitmap, pool->bitlimit); +} + +/* This finds n contiguous free ids, allocates and returns the first one */ +int ids_new_contiguous(struct id_pool *pool, int numids) +{ + int id = find_and_set_first_free_contig_bits(pool->bitmap, + pool->bitlimit, + numids); + if (id < 0) + printf("%s: Warning! New id alloc failed\n", __FUNCTION__); + return id; +} + +/* This deletes a list of contiguous ids given the first one and number of ids */ +int ids_del_contiguous(struct id_pool *pool, int first, int numids) +{ + int ret; + + if (pool->nwords * WORD_BITS < first + numids) + return -1; + if ((ret = check_and_clear_contig_bits(pool->bitmap, first, numids))) + printf("%s: Error: Invalid argument range.\n", __FUNCTION__); + return ret; +} + +int id_del(struct id_pool *pool, int id) +{ + int ret; + + if (pool->nwords * WORD_BITS < id) + return -1; + + if ((ret = check_and_clear_bit(pool->bitmap, id) < 0)) + printf("%s: Error: Could not delete id.\n", __FUNCTION__); + return ret; +} + +/* Return a specific id, if available */ +int id_get(struct id_pool *pool, int id) +{ + int ret; + + ret = check_and_set_bit(pool->bitmap, id); + + if (ret < 0) + return ret; + else + return id; +} + +int id_is_empty(struct id_pool *pool) +{ + for (int i = 0; i < pool->nwords; i++) + if (pool->bitmap[i]) + return 0; + return 1; +} + diff --git a/conts/libl4thread/src/stack.c b/conts/libl4thread/src/stack.c new file mode 100644 index 0000000..5fedcba --- /dev/null +++ b/conts/libl4thread/src/stack.c @@ -0,0 +1,97 @@ +/* + * Stack management in libl4thread. + * + * Copyright © 2009 B Labs Ltd. + */ +#include +#include +#include +#include +#include + +/* Extern declarations */ +extern struct l4_mutex lib_mutex; + +/* Global variables */ +unsigned long lib_stack_size; + +/* Stack virtual region pool */ +static struct address_pool stack_region_pool; + +int stack_pool_init(unsigned long stack_start, + unsigned long stack_end, + unsigned long stack_size) +{ + int err; + + /* Initialise the global stack virtual address pool. */ + if ((err = address_pool_init(&stack_region_pool, + stack_start, stack_end, + stack_size) < 0)) { + printf("Stack address pool initialisation failed.\n"); + return err; + } + + return 0; +} + +void *get_stack_space(void) +{ + return address_new(&stack_region_pool, 1, lib_stack_size); +} + +int delete_stack_space(void *stack_address) +{ + return address_del(&stack_region_pool, stack_address, 1, lib_stack_size); +} + +int l4_set_stack_params(unsigned long stack_top, + unsigned long stack_bottom, + unsigned long stack_size) +{ + /* Ensure that arguments are valid. */ + if (IS_STACK_SETUP()) { + printf("libl4thread: You have already called: %s.\n", + __FUNCTION__); + return -EPERM; + } + if (!stack_top || !stack_bottom) { + printf("libl4thread: Stack address range cannot contain " + "0x0 as a start and/or end address(es).\n"); + return -EINVAL; + } + // FIXME: Aligning should be taken into account. + /* + * Stack grows downward so the top of the stack will have + * the lowest numbered address. + */ + if (stack_top >= stack_bottom) { + printf("libl4thread: Stack bottom address must be bigger " + "than stack top address.\n"); + return -EINVAL; + } + if (!stack_size) { + printf("libl4thread: Stack size cannot be zero.\n"); + return -EINVAL; + } + /* stack_size at least must be equal to the difference. */ + if ((stack_bottom - stack_top) < stack_size) { + printf("libl4thread: The given range size is lesser than " + "the stack size(0x%x).\n", stack_size); + return -EINVAL; + } + /* Arguments passed the validity tests. */ + + /* Initialize internal variables. */ + lib_stack_size = stack_size; + + /* Initialize stack virtual address pool. */ + if (stack_pool_init(stack_top, stack_bottom, stack_size) < 0) + BUG(); + + /* Initialize the global mutex. */ + l4_mutex_init(&lib_mutex); + + return 0; +} + diff --git a/conts/libl4thread/src/tcb.c b/conts/libl4thread/src/tcb.c index d0125bb..dec4918 100644 --- a/conts/libl4thread/src/tcb.c +++ b/conts/libl4thread/src/tcb.c @@ -1,3 +1,8 @@ +/* + * Thread management in libl4thread. + * + * Copyright (C) 2009 B Labs Ltd. + */ #include #include #include @@ -5,50 +10,53 @@ #include /* Global task list. */ -struct l4t_global_list l4t_global_tasks = { - .list = { &l4t_global_tasks.list, &l4t_global_tasks.list }, +struct global_list global_tasks = { + .list = { &global_tasks.list, &global_tasks.list }, .total = 0, }; /* Function definitions */ -void l4t_global_add_task(struct l4t_tcb *task) +void global_add_task(struct tcb *task) { BUG_ON(!list_empty(&task->list)); - list_insert_tail(&task->list, &l4t_global_tasks.list); - l4t_global_tasks.total++; + list_insert_tail(&task->list, &global_tasks.list); + global_tasks.total++; } -void l4t_global_remove_task(struct l4t_tcb *task) +void global_remove_task(struct tcb *task) { BUG_ON(list_empty(&task->list)); list_remove_init(&task->list); - BUG_ON(--l4t_global_tasks.total < 0); + BUG_ON(--global_tasks.total < 0); } -struct l4t_tcb *l4t_find_task(int tid) +struct tcb *find_task(int tid) { - struct l4t_tcb *t; + struct tcb *t; - list_foreach_struct(t, &l4t_global_tasks.list, list) + list_foreach_struct(t, &global_tasks.list, list) if (t->tid == tid) return t; return 0; } -struct l4t_tcb *l4t_tcb_alloc_init(struct l4t_tcb *parent, unsigned int flags) +struct tcb *tcb_alloc_init(struct tcb *parent, unsigned int flags) { - struct l4t_tcb *task; + struct tcb *task; - if (!(task = kzalloc(sizeof(struct l4t_tcb)))) + if (!(task = kzalloc(sizeof(struct tcb)))) return PTR_ERR(-ENOMEM); link_init(&task->list); - if ((parent) && (flags & TC_SHARE_SPACE)) + if (flags & TC_SHARE_SPACE) task->utcb_head = parent->utcb_head; else { - if (!(task->utcb_head = kzalloc(sizeof(struct utcb_head)))) + /* COPY or NEW space */ + if (!(task->utcb_head = kzalloc(sizeof(struct utcb_head)))) { + kfree(task); return PTR_ERR(-ENOMEM); + } link_init(&task->utcb_head->list); } diff --git a/conts/libl4thread/src/thread.c b/conts/libl4thread/src/thread.c index 87e84b4..61b0f53 100644 --- a/conts/libl4thread/src/thread.c +++ b/conts/libl4thread/src/thread.c @@ -5,181 +5,206 @@ */ #include #include +#include #include +#include #include #include #include #include - -/* Symbolic constants and macros */ -#define IS_STACK_SETUP() (lib_stack_size) +#include /* Extern declarations */ extern void setup_new_thread(void); +extern unsigned long lib_stack_size; +extern unsigned long lib_utcb_range_size; /* Static variable definitions */ -static unsigned long lib_stack_top_addr; -static unsigned long lib_stack_bot_addr; -static unsigned long lib_stack_size; +struct l4_mutex lib_mutex; /* Function definitions */ -int set_stack_params(unsigned long stack_top, - unsigned long stack_bottom, - unsigned long stack_size) -{ - /* Ensure that arguments are valid. */ - if (IS_STACK_SETUP()) { - printf("libl4thread: You have already called: %s.\n", - __FUNCTION__); - return -EPERM; - } - if (!stack_top || !stack_bottom) { - printf("libl4thread: Stack address range cannot contain " - "0x0 as a start and/or end address(es).\n"); - return -EINVAL; - } - // FIXME: Aligning should be taken into account. - /* - * Stack grows downward so the top of the stack will have - * the lowest numbered address. - */ - if (stack_top >= stack_bottom) { - printf("libl4thread: Stack bottom address must be bigger " - "than stack top address.\n"); - return -EINVAL; - } - if (!stack_size) { - printf("libl4thread: Stack size cannot be zero.\n"); - return -EINVAL; - } - /* stack_size at least must be equal to the difference. */ - if ((stack_bottom - stack_top) < stack_size) { - printf("libl4thread: The given range size is lesser than " - "the stack size(0x%x).\n", stack_size); - return -EINVAL; - } - /* Arguments passed the validity tests. */ - - /* Initialize internal variables */ - lib_stack_bot_addr = stack_bottom; - lib_stack_top_addr = stack_top; - lib_stack_size = stack_size; - - return 0; -} - -int l4thread_create(struct task_ids *ids, unsigned int flags, +int l4_thread_create(struct task_ids *ids, unsigned int flags, int (*func)(void *), void *arg) { struct exregs_data exregs; unsigned long utcb_addr; - struct l4t_tcb *parent, *child; - int err; + struct tcb *parent, *child; + unsigned long stack_top_addr, stack_bot_addr; + int err = 0; /* A few controls before granting access to thread creation */ - // FIXME: check if utcb region is setup - if (!IS_STACK_SETUP()) { + if (!IS_STACK_SETUP() || !IS_UTCB_SETUP()) { printf("libl4thread: Stack and/or utcb have not been " - "set up.\n"); + "set up.\n"); return -EPERM; } - /* Is there enough stack space for the new thread? */ - if (lib_stack_top_addr >= lib_stack_bot_addr) { - printf("libl4thread: No stack space left.\n"); - return -ENOMEM; - } - - // FIXME: Check if there is enough utcb space - - if (!(TC_SHARE_SPACE & flags)) { - printf("libl4thread: Only allows shared space thread " - "creation.\n"); - - return -EINVAL; - } + /* Before doing any operation get the global mutex. */ + l4_mutex_lock(&lib_mutex); /* Get parent's ids and find the tcb belonging to it. */ l4_getid(ids); - if (!(parent = l4t_find_task(ids->tid))) - return-ESRCH; + if (!(parent = find_task(ids->tid))) { + err = -ESRCH; + goto out_err1; + } /* Allocate tcb for the child. */ - if (!(child = l4t_tcb_alloc_init(parent, flags))) { + if (!(child = tcb_alloc_init(parent, flags))) { + // FIXME: What happens to utcb_head printf("libl4thread: No heap space left.\n"); - return -ENOMEM; + err = -ENOMEM; + goto out_err1; } - /* Get a utcb addr for this thread */ + /* Get a utcb addr. */ if (!(utcb_addr = get_utcb_addr(child))) { - printf("libl4thread: No utcb address left.\n"); - // FIXME: Check if there is any memory leak - kfree(child); - return -ENOMEM; + printf("libl4thread: No utcb space left.\n"); + err = -ENOMEM; + goto out_err2; } + /* Get a stack space and calculate the bottom addr of the stack. */ + stack_top_addr = (unsigned long)get_stack_space(); + if (!stack_top_addr) { + printf("libl4thread: No stack space left.\n"); + err = -ENOMEM; + goto out_err3; + } + stack_bot_addr = stack_top_addr + lib_stack_size; + child->stack_addr = stack_top_addr; + /* Create thread */ if ((err = l4_thread_control(THREAD_CREATE | flags, ids)) < 0) { printf("libl4thread: l4_thread_control(THREAD_CREATE) " - "failed with (%d).\n", err); - // FIXME: Check if there is any memory leak - kfree(child); - delete_utcb_addr(child); - return err; + "failed with (%d).\n", err); + goto out_err4; } /* Setup new thread pc, sp, utcb */ memset(&exregs, 0, sizeof(exregs)); - exregs_set_stack(&exregs, align((lib_stack_bot_addr - 1), 8)); + exregs_set_stack(&exregs, align((stack_bot_addr - 1), 8)); exregs_set_pc(&exregs, (unsigned long)setup_new_thread); exregs_set_utcb(&exregs, (unsigned long)utcb_addr); if ((err = l4_exchange_registers(&exregs, ids->tid)) < 0) { printf("libl4thread: l4_exchange_registers failed with " - "(%d).\n", err); - // FIXME: Check if there is any memory leak - return err; + "(%d).\n", err); + goto out_err5; } /* First word of new stack is arg */ - ((unsigned long *)align((lib_stack_bot_addr - 1), 8))[0] = - (unsigned long)arg; + ((unsigned long *)align((stack_bot_addr - 1), 8))[0] = + (unsigned long)arg; /* Second word of new stack is function address */ - ((unsigned long *)align((lib_stack_bot_addr - 1), 8))[-1] = - (unsigned long)func; - /* Update the stack address */ - lib_stack_bot_addr -= lib_stack_size; + ((unsigned long *)align((stack_bot_addr - 1), 8))[-1] = + (unsigned long)func; /* Add child to the global task list */ child->tid = ids->tid; - l4t_global_add_task(child); + global_add_task(child); /* Start the new thread */ if ((err = l4_thread_control(THREAD_RUN, ids)) < 0) { printf("libl4thread: l4_thread_control(THREAD_RUN) " - "failed with (%d).\n", err); - return err; + "failed with (%d).\n", err); + goto out_err6; } + /* Release the global mutex. */ + l4_mutex_unlock(&lib_mutex); + return 0; + + /* Error handling. */ +out_err6: + global_remove_task(child); +out_err5: + l4_thread_control(THREAD_DESTROY, ids); +out_err4: + delete_stack_space((void *)child->stack_addr); +out_err3: + delete_utcb_addr(child); +out_err2: + if ((flags & TC_COPY_SPACE) || (flags & TC_NEW_SPACE)) + kfree(child->utcb_head); + kfree(child); +out_err1: + l4_mutex_unlock(&lib_mutex); + + return err; } -void l4thread_kill(struct task_ids *ids) +void l4_thread_exit(int retval) { - struct l4t_tcb *task; + struct tcb *task; + struct task_ids ids; - /* Find the task to be killed. */ - task = l4t_find_task(ids->tid); + /* Before doing any operation get the global mutex. */ + l4_mutex_lock(&lib_mutex); + + /* Find the task. */ + l4_getid(&ids); + /* Cant find the thread means it wasnt added to the list. */ + if (!(task = find_task(ids.tid))) + BUG(); + + /* Remove child from the global task list. */ + global_remove_task(task); + + /* Delete the stack space. */ + if (delete_stack_space((void *)task->stack_addr) < 0) + BUG(); /* Delete the utcb address. */ delete_utcb_addr(task); + // FIXME: We assume that main thread never leaves the scene + // FIXME: What happens to task->utcb_head? + kfree(task); + + /* Release the global mutex. */ + l4_mutex_unlock(&lib_mutex); + + /* Relinquish the control. */ + l4_exit(retval); + + /* Should never reach here. */ + BUG(); +} + +int l4_thread_kill(struct task_ids *ids) +{ + struct tcb *task; + + /* Before doing any operation get the global mutex. */ + l4_mutex_lock(&lib_mutex); + + /* Find the task to be killed. */ + if (!(task = find_task(ids->tid))) { + l4_mutex_unlock(&lib_mutex); + return -ESRCH; + } + /* Remove child from the global task list. */ - l4t_global_remove_task(task); + global_remove_task(task); + + /* Delete the stack space. */ + if (delete_stack_space((void *)task->stack_addr) < 0) + BUG(); + + /* Delete the utcb address. */ + delete_utcb_addr(task); // FIXME: We assume that main thread never leaves the scene + // FIXME: What happens to task->utcb_head? kfree(task); + /* Release the global mutex. */ + l4_mutex_unlock(&lib_mutex); + /* Finally, destroy the thread. */ l4_thread_control(THREAD_DESTROY, ids); + + return 0; } diff --git a/conts/libl4thread/src/utcb-common.c b/conts/libl4thread/src/utcb-common.c index 38df843..5ad511a 100644 --- a/conts/libl4thread/src/utcb-common.c +++ b/conts/libl4thread/src/utcb-common.c @@ -1,7 +1,7 @@ /* - * UTCB management in Codezero + * UTCB management in libl4thread. * - * Copyright © 2009 B Labs Ltd + * Copyright © 2009 B Labs Ltd. */ #include #include @@ -18,7 +18,7 @@ int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end) /* Initialise the global utcb virtual address pool */ if ((err = address_pool_init(&utcb_region_pool, utcb_start, utcb_end, - UTCB_SIZE) < 0)) { + PAGE_SIZE) < 0)) { printf("UTCB address pool initialisation failed.\n"); return err; } @@ -26,14 +26,14 @@ int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end) return 0; } -static inline void *utcb_new_address(int npages) +static inline void *utcb_new_address(int nitems) { - return address_new(&utcb_region_pool, npages); + return address_new(&utcb_region_pool, nitems, PAGE_SIZE); } -static inline int utcb_delete_address(void *utcb_address, int npages) +static inline int utcb_delete_address(void *utcb_address, int nitems) { - return address_del(&utcb_region_pool, utcb_address, npages); + return address_del(&utcb_region_pool, utcb_address, nitems, PAGE_SIZE); } /* Return an empty utcb slot in this descriptor */ @@ -72,7 +72,11 @@ struct utcb_desc *utcb_new_desc(void) /* Obtain a new and unique utcb base */ /* FIXME: Use variable size than a page */ - d->utcb_base = (unsigned long)utcb_new_address(1); + if (!(d->utcb_base = (unsigned long)utcb_new_address(1))) { + kfree(d->slots); + kfree(d); + return 0; + } return d; } diff --git a/conts/libl4thread/src/utcb.c b/conts/libl4thread/src/utcb.c index 4dd7fef..5bed78c 100644 --- a/conts/libl4thread/src/utcb.c +++ b/conts/libl4thread/src/utcb.c @@ -1,5 +1,5 @@ /* - * UTCB handling helper routines + * UTCB handling helper routines. * * Copyright (C) 2009 B Labs Ltd. */ @@ -13,10 +13,13 @@ #include /* Extern declarations */ -extern struct l4t_global_list l4t_global_tasks; +extern struct global_list global_tasks; + +/* Global variables */ +unsigned long lib_utcb_range_size; /* Function definitions */ -unsigned long get_utcb_addr(struct l4t_tcb *task) +unsigned long get_utcb_addr(struct tcb *task) { struct utcb_desc *udesc; unsigned long slot; @@ -30,7 +33,8 @@ unsigned long get_utcb_addr(struct l4t_tcb *task) goto found; /* Allocate a new utcb memory region and return its base. */ - udesc = utcb_new_desc(); + if (!(udesc = utcb_new_desc())) + return 0; slot = utcb_new_slot(udesc); list_insert(&udesc->list, &task->utcb_head->list); found: @@ -39,7 +43,7 @@ found: return slot; } -int delete_utcb_addr(struct l4t_tcb *task) +int delete_utcb_addr(struct tcb *task) { struct utcb_desc *udesc; @@ -68,55 +72,56 @@ static int set_utcb_addr(void) { struct exregs_data exregs; struct task_ids ids; - struct l4t_tcb *task; + struct tcb *task; struct utcb_desc *udesc; int err; /* Create a task. */ - if (IS_ERR(task = l4t_tcb_alloc_init(0, 0))) + if (IS_ERR(task = tcb_alloc_init(0, 0))) return -ENOMEM; /* Add child to the global task list. */ - list_insert_tail(&task->list, &l4t_global_tasks.list); - l4t_global_tasks.total++; + list_insert_tail(&task->list, &global_tasks.list); + global_tasks.total++; - udesc = utcb_new_desc(); + if (!(udesc = utcb_new_desc())) + return -ENOMEM; task->utcb_addr = utcb_new_slot(udesc); list_insert(&udesc->list, &task->utcb_head->list); memset(&exregs, 0, sizeof(exregs)); - exregs_set_utcb(&exregs, (unsigned long)task->utcb_addr); + exregs_set_utcb(&exregs, task->utcb_addr); l4_getid(&ids); + task->tid = ids.tid; if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) { printf("libl4thread: l4_exchange_registers failed with " - "(%d).\n", err); + "(%d).\n", err); return err; } return 0; } -int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) +int l4_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) { int err; /* Ensure that arguments are valid. */ - // FIXME: Check if set_utcb_params is called - /*if (IS_UTCB_SETUP()) {*/ - /*printf("libl4thread: You have already called: %s.\n",*/ - /*__FUNCTION__);*/ - /*return -EPERM;*/ - /*}*/ + if (IS_UTCB_SETUP()) { + printf("libl4thread: You have already called: %s.\n", + __FUNCTION__); + return -EPERM; + } if (!utcb_start || !utcb_end) { printf("libl4thread: Utcb address range cannot contain " "0x0 as a start and/or end address(es).\n"); return -EINVAL; } - /* Check if the start address is aligned on UTCB_SIZE. */ - if (utcb_start & !UTCB_SIZE) { + /* Check if the start address is aligned on PAGE_SIZE. */ + if (utcb_start & PAGE_MASK) { printf("libl4thread: Utcb start address must be aligned " - "on UTCB_SIZE(0x%x).\n", UTCB_SIZE); + "on PAGE_SIZE(0x%x).\n", PAGE_SIZE); return -EINVAL; } /* The range must be a valid one. */ @@ -128,7 +133,7 @@ int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) /* * This check guarantees two things: * 1. The range must be multiple of UTCB_SIZE, at least one item. - * 2. utcb_end is aligned on UTCB_SIZE + * 2. utcb_end is aligned on UTCB_SIZE. */ if ((utcb_end - utcb_start) % UTCB_SIZE) { printf("libl4thread: The given range size must be multiple " @@ -137,12 +142,19 @@ int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) } /* Arguments passed the validity tests. */ - /* Init utcb virtual address pool */ - utcb_pool_init(utcb_start, utcb_end); + /* Init utcb virtual address pool. */ + if (utcb_pool_init(utcb_start, utcb_end) < 0) + BUG(); - /* The very first thread's utcb address is assigned. */ + /* + * The very first thread's utcb address is assigned. + * It should not return an error value. + */ if ((err = set_utcb_addr()) < 0) - return err; + BUG(); + + /* Initialize internal variables. */ + lib_utcb_range_size = utcb_end - utcb_start; return 0; }