From 871d40a6b405ada132429af496d767987e56ccba Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Fri, 13 Nov 2009 12:32:33 +0200 Subject: [PATCH 01/19] Trying to fix merge / revert problems related to the thread library. Revert "Merge branch 'libl4thread' of git://www.b-labs.co.uk/bora/git/codezero into bora" This reverts commit dc7fd0d24d8e753e1803c826a6ddfaf90c143823. --- conts/libl4thread/include/l4thread/addr.h | 27 --- conts/libl4thread/include/l4thread/tcb.h | 35 ---- conts/libl4thread/include/l4thread/thread.h | 18 -- .../include/l4thread/utcb-common.h | 25 --- conts/libl4thread/include/l4thread/utcb.h | 14 -- conts/libl4thread/src/addr.c | 57 ------ conts/libl4thread/src/tcb.c | 56 ------ conts/libl4thread/src/thread.c | 185 ------------------ conts/libl4thread/src/utcb-common.c | 89 --------- conts/libl4thread/src/utcb.c | 148 -------------- 10 files changed, 654 deletions(-) delete mode 100644 conts/libl4thread/include/l4thread/addr.h delete mode 100644 conts/libl4thread/include/l4thread/tcb.h delete mode 100644 conts/libl4thread/include/l4thread/thread.h delete mode 100644 conts/libl4thread/include/l4thread/utcb-common.h delete mode 100644 conts/libl4thread/include/l4thread/utcb.h delete mode 100644 conts/libl4thread/src/addr.c delete mode 100644 conts/libl4thread/src/tcb.c delete mode 100644 conts/libl4thread/src/thread.c delete mode 100644 conts/libl4thread/src/utcb-common.c delete mode 100644 conts/libl4thread/src/utcb.c diff --git a/conts/libl4thread/include/l4thread/addr.h b/conts/libl4thread/include/l4thread/addr.h deleted file mode 100644 index e7b4519..0000000 --- a/conts/libl4thread/include/l4thread/addr.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Address allocation pool - * - * Copyright (C) 2007 Bahadir Balban - */ -#ifndef __ADDR_H__ -#define __ADDR_H__ - -#include - -/* Address pool to allocate from a range of addresses */ -struct address_pool { - struct id_pool *idpool; - unsigned long start; - unsigned long end; -}; - -int address_pool_init_with_idpool(struct address_pool *pool, - struct id_pool *idpool, - unsigned long start, unsigned long end); -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); - -#endif /* __ADDR_H__ */ diff --git a/conts/libl4thread/include/l4thread/tcb.h b/conts/libl4thread/include/l4thread/tcb.h deleted file mode 100644 index 1c81111..0000000 --- a/conts/libl4thread/include/l4thread/tcb.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Thread control block. - * - * Copyright (C) 2009 B Labs Ltd. - */ -#ifndef __LIB_TCB_H__ -#define __LIB_TCB_H__ - -#include - -/* Keeps all the struct utcb_descs belonging to a thread group together. */ -struct utcb_head { - struct link list; -}; - -/* A simple thread control block for the thread library. */ -struct l4t_tcb { - struct link list; - int tid; - struct utcb_head *utcb_head; - unsigned long utcb_addr; -}; - -/* This struct keeps track of all the threads handled by the thread lib. */ -struct l4t_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); - -#endif /* __LIB_TCB_H__ */ diff --git a/conts/libl4thread/include/l4thread/thread.h b/conts/libl4thread/include/l4thread/thread.h deleted file mode 100644 index 319233e..0000000 --- a/conts/libl4thread/include/l4thread/thread.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Thread creation userspace helpers - * - * Copyright (C) 2009 B Labs Ltd. - */ -#ifndef __LIB_THREAD_H__ -#define __LIB_THREAD_H__ - -int 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 l4thread_create(struct task_ids *ids, unsigned int flags, - int (*func)(void *), void *arg); -void l4thread_kill(struct task_ids *ids); - -#endif /* __LIB_THREAD_H__ */ diff --git a/conts/libl4thread/include/l4thread/utcb-common.h b/conts/libl4thread/include/l4thread/utcb-common.h deleted file mode 100644 index e5f5fef..0000000 --- a/conts/libl4thread/include/l4thread/utcb-common.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * UTCB handling common helper routines - * - * Copyright (C) 2009 B Labs Ltd. - */ -#ifndef __UTCB_COMMON_H__ -#define __UTCB_COMMON_H__ - -#include - -struct utcb_desc { - struct link list; - unsigned long utcb_base; - struct id_pool *slots; -}; - -int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end); - -unsigned long utcb_new_slot(struct utcb_desc *desc); -int utcb_delete_slot(struct utcb_desc *desc, unsigned long address); - -struct utcb_desc *utcb_new_desc(void); -int utcb_delete_desc(struct utcb_desc *desc); - -#endif /* __UTCB_COMMON_H__ */ diff --git a/conts/libl4thread/include/l4thread/utcb.h b/conts/libl4thread/include/l4thread/utcb.h deleted file mode 100644 index f16f310..0000000 --- a/conts/libl4thread/include/l4thread/utcb.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * UTCB handling helper routines - * - * Copyright (C) 2009 B Labs Ltd. - */ -#ifndef __LIB_UTCB_H__ -#define __LIB_UTCB_H__ - -#include - -unsigned long get_utcb_addr(struct l4t_tcb *task); -int delete_utcb_addr(struct l4t_tcb *task); - -#endif /* __LIB_UTCB_H__ */ diff --git a/conts/libl4thread/src/addr.c b/conts/libl4thread/src/addr.c deleted file mode 100644 index 90c67dd..0000000 --- a/conts/libl4thread/src/addr.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This module allocates an unused address range from - * a given memory region defined as the pool range. - * - * Copyright (C) 2007 Bahadir Balban - */ -#include -#include - -/* - * Initializes an address pool, but uses an already - * allocated id pool for it. - */ -int address_pool_init_with_idpool(struct address_pool *pool, - struct id_pool *idpool, - unsigned long start, unsigned long end) -{ - pool->idpool = idpool; - pool->start = start; - pool->end = end; - - return 0; -} - -int address_pool_init(struct address_pool *pool, - unsigned long start, unsigned long end, - int size) -{ - if ((pool->idpool = id_pool_new_init((end - start) / size)) < 0) - return (int)pool->idpool; - pool->start = start; - pool->end = end; - return 0; -} - -void *address_new(struct address_pool *pool, int npages) -{ - unsigned int pfn; - - if ((int)(pfn = ids_new_contiguous(pool->idpool, npages)) < 0) - return 0; - - return (void *)__pfn_to_addr(pfn) + pool->start; -} - -int address_del(struct address_pool *pool, void *addr, int npages) -{ - unsigned long pfn = __pfn(page_align(addr) - pool->start); - - if (ids_del_contiguous(pool->idpool, pfn, npages) < 0) { - printf("%s: Invalid address range returned to " - "virtual address pool.\n", __FUNCTION__); - return -1; - } - return 0; -} - diff --git a/conts/libl4thread/src/tcb.c b/conts/libl4thread/src/tcb.c deleted file mode 100644 index d0125bb..0000000 --- a/conts/libl4thread/src/tcb.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include -#include -#include - -/* Global task list. */ -struct l4t_global_list l4t_global_tasks = { - .list = { &l4t_global_tasks.list, &l4t_global_tasks.list }, - .total = 0, -}; - -/* Function definitions */ -void l4t_global_add_task(struct l4t_tcb *task) -{ - BUG_ON(!list_empty(&task->list)); - list_insert_tail(&task->list, &l4t_global_tasks.list); - l4t_global_tasks.total++; -} - -void l4t_global_remove_task(struct l4t_tcb *task) -{ - BUG_ON(list_empty(&task->list)); - list_remove_init(&task->list); - BUG_ON(--l4t_global_tasks.total < 0); -} - -struct l4t_tcb *l4t_find_task(int tid) -{ - struct l4t_tcb *t; - - list_foreach_struct(t, &l4t_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 l4t_tcb *task; - - if (!(task = kzalloc(sizeof(struct l4t_tcb)))) - return PTR_ERR(-ENOMEM); - - link_init(&task->list); - - if ((parent) && (flags & TC_SHARE_SPACE)) - task->utcb_head = parent->utcb_head; - else { - if (!(task->utcb_head = kzalloc(sizeof(struct utcb_head)))) - return PTR_ERR(-ENOMEM); - link_init(&task->utcb_head->list); - } - - return task; -} diff --git a/conts/libl4thread/src/thread.c b/conts/libl4thread/src/thread.c deleted file mode 100644 index 87e84b4..0000000 --- a/conts/libl4thread/src/thread.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Thread creation userspace helpers - * - * Copyright (C) 2009 B Labs Ltd. - */ -#include -#include -#include -#include -#include -#include -#include - -/* Symbolic constants and macros */ -#define IS_STACK_SETUP() (lib_stack_size) - -/* Extern declarations */ -extern void setup_new_thread(void); - -/* Static variable definitions */ -static unsigned long lib_stack_top_addr; -static unsigned long lib_stack_bot_addr; -static unsigned long lib_stack_size; - -/* 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 (*func)(void *), void *arg) -{ - struct exregs_data exregs; - unsigned long utcb_addr; - struct l4t_tcb *parent, *child; - int err; - - /* A few controls before granting access to thread creation */ - // FIXME: check if utcb region is setup - if (!IS_STACK_SETUP()) { - printf("libl4thread: Stack and/or utcb have not been " - "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; - } - - /* Get parent's ids and find the tcb belonging to it. */ - l4_getid(ids); - if (!(parent = l4t_find_task(ids->tid))) - return-ESRCH; - - /* Allocate tcb for the child. */ - if (!(child = l4t_tcb_alloc_init(parent, flags))) { - printf("libl4thread: No heap space left.\n"); - return -ENOMEM; - } - - /* Get a utcb addr for this thread */ - 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; - } - - /* 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; - } - - /* Setup new thread pc, sp, utcb */ - memset(&exregs, 0, sizeof(exregs)); - exregs_set_stack(&exregs, align((lib_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; - } - - /* First word of new stack is arg */ - ((unsigned long *)align((lib_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; - - /* Add child to the global task list */ - child->tid = ids->tid; - l4t_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; - } - - return 0; -} - -void l4thread_kill(struct task_ids *ids) -{ - struct l4t_tcb *task; - - /* Find the task to be killed. */ - task = l4t_find_task(ids->tid); - - /* Delete the utcb address. */ - delete_utcb_addr(task); - - /* Remove child from the global task list. */ - l4t_global_remove_task(task); - - // FIXME: We assume that main thread never leaves the scene - kfree(task); - - /* Finally, destroy the thread. */ - l4_thread_control(THREAD_DESTROY, ids); -} diff --git a/conts/libl4thread/src/utcb-common.c b/conts/libl4thread/src/utcb-common.c deleted file mode 100644 index 38df843..0000000 --- a/conts/libl4thread/src/utcb-common.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * UTCB management in Codezero - * - * Copyright © 2009 B Labs Ltd - */ -#include -#include -#include -#include - -/* Globally disjoint utcb virtual region pool */ -static struct address_pool utcb_region_pool; - -int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end) -{ - int err; - - /* Initialise the global utcb virtual address pool */ - if ((err = address_pool_init(&utcb_region_pool, - utcb_start, utcb_end, - UTCB_SIZE) < 0)) { - printf("UTCB address pool initialisation failed.\n"); - return err; - } - - return 0; -} - -static inline void *utcb_new_address(int npages) -{ - return address_new(&utcb_region_pool, npages); -} - -static inline int utcb_delete_address(void *utcb_address, int npages) -{ - return address_del(&utcb_region_pool, utcb_address, npages); -} - -/* Return an empty utcb slot in this descriptor */ -unsigned long utcb_new_slot(struct utcb_desc *desc) -{ - int slot; - - if ((slot = id_new(desc->slots)) < 0) - return 0; - else - return desc->utcb_base + (unsigned long)slot * UTCB_SIZE; -} - -int utcb_delete_slot(struct utcb_desc *desc, unsigned long address) -{ - BUG_ON(id_del(desc->slots, (address - desc->utcb_base) - / UTCB_SIZE) < 0); - return 0; -} - -struct utcb_desc *utcb_new_desc(void) -{ - struct utcb_desc *d; - - /* Allocate a new descriptor */ - if (!(d = kzalloc(sizeof(*d)))) - return 0; - - link_init(&d->list); - - /* We currently assume UTCB is smaller than PAGE_SIZE */ - BUG_ON(UTCB_SIZE > PAGE_SIZE); - - /* Initialise utcb slots */ - d->slots = id_pool_new_init(PAGE_SIZE / UTCB_SIZE); - - /* Obtain a new and unique utcb base */ - /* FIXME: Use variable size than a page */ - d->utcb_base = (unsigned long)utcb_new_address(1); - - return d; -} - -int utcb_delete_desc(struct utcb_desc *desc) -{ - /* Return descriptor address */ - utcb_delete_address((void *)desc->utcb_base, 1); - - /* Free the descriptor */ - kfree(desc); - - return 0; -} diff --git a/conts/libl4thread/src/utcb.c b/conts/libl4thread/src/utcb.c deleted file mode 100644 index 4dd7fef..0000000 --- a/conts/libl4thread/src/utcb.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * UTCB handling helper routines - * - * Copyright (C) 2009 B Labs Ltd. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* Extern declarations */ -extern struct l4t_global_list l4t_global_tasks; - -/* Function definitions */ -unsigned long get_utcb_addr(struct l4t_tcb *task) -{ - struct utcb_desc *udesc; - unsigned long slot; - - /* Setting this up twice is a bug. */ - BUG_ON(task->utcb_addr); - - /* Search for an empty utcb slot already allocated to this space. */ - list_foreach_struct(udesc, &task->utcb_head->list, list) - if ((slot = utcb_new_slot(udesc))) - goto found; - - /* Allocate a new utcb memory region and return its base. */ - udesc = utcb_new_desc(); - slot = utcb_new_slot(udesc); - list_insert(&udesc->list, &task->utcb_head->list); -found: - task->utcb_addr = slot; - - return slot; -} - -int delete_utcb_addr(struct l4t_tcb *task) -{ - struct utcb_desc *udesc; - - list_foreach_struct(udesc, &task->utcb_head->list, list) { - /* FIXME: Use variable alignment than a page */ - /* Detect matching slot */ - if (page_align(task->utcb_addr) == udesc->utcb_base) { - - /* Delete slot from the descriptor */ - utcb_delete_slot(udesc, task->utcb_addr); - - /* Is the desc completely empty now? */ - if (id_is_empty(udesc->slots)) { - /* Unlink desc from its list */ - list_remove_init(&udesc->list); - /* Delete the descriptor */ - utcb_delete_desc(udesc); - } - return 0; /* Finished */ - } - } - BUG(); -} - -static int set_utcb_addr(void) -{ - struct exregs_data exregs; - struct task_ids ids; - struct l4t_tcb *task; - struct utcb_desc *udesc; - int err; - - /* Create a task. */ - if (IS_ERR(task = l4t_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++; - - udesc = utcb_new_desc(); - 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); - - l4_getid(&ids); - if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) { - printf("libl4thread: l4_exchange_registers failed with " - "(%d).\n", err); - return err; - } - - return 0; -} - -int 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 (!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) { - printf("libl4thread: Utcb start address must be aligned " - "on UTCB_SIZE(0x%x).\n", UTCB_SIZE); - return -EINVAL; - } - /* The range must be a valid one. */ - if (utcb_start >= utcb_end) { - printf("libl4thread: Utcb end address must be bigger " - "than utcb start address.\n"); - return -EINVAL; - } - /* - * 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 - */ - if ((utcb_end - utcb_start) % UTCB_SIZE) { - printf("libl4thread: The given range size must be multiple " - "of the utcb size(%d).\n", UTCB_SIZE); - return -EINVAL; - } - /* Arguments passed the validity tests. */ - - /* Init utcb virtual address pool */ - utcb_pool_init(utcb_start, utcb_end); - - /* The very first thread's utcb address is assigned. */ - if ((err = set_utcb_addr()) < 0) - return err; - - return 0; -} From bb6dd492e0d97b7fab143b0fd1eafd7577358972 Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Wed, 28 Oct 2009 14:11:43 +0200 Subject: [PATCH 02/19] Bare container type is converted to Examples container type. Examples container type is designed to keep applications using codezero userspace libraries, which is aiming to help newcomers who would like to develop programs on top of the l4 microkernel. Now bare bone application is one of the examples. In the near future, lots of new programs will be introduced to show the various aspects of codezero eco-system. --- config/cml/container_ruleset.template | 34 ++++++++---- config/configuration.py | 9 ++- configure.py | 8 +-- .../example0}/SConstruct | 32 +++++------ .../example0}/container.c | 2 +- .../example0}/include/test.h | 0 conts/examples/example0/main.c | 12 ++++ .../example0}/src/test.c | 0 conts/examples/example1/SConstruct | 55 +++++++++++++++++++ conts/examples/example1/container.c | 21 +++++++ conts/{bare_src => examples/example1}/hello.c | 0 .../examples/example1/include/test.h | 0 conts/{bare_src => examples/example1}/main.c | 0 .../examples/example1/src/test.c | 0 scripts/conts/containers.py | 6 +- scripts/examples/__init__.py | 0 .../examples_generator.py} | 49 +++++++++-------- scripts/examples/files/SConstruct.in | 0 .../{bare => examples}/files/build.readme.in | 0 .../files/container.desc.in | 0 .../{bare => examples}/files/container.h.in | 0 .../{bare => examples}/files/linker.lds.in | 0 22 files changed, 162 insertions(+), 66 deletions(-) rename conts/{bare_src => examples/example0}/SConstruct (53%) rename conts/{bare_src => examples/example0}/container.c (91%) rename conts/{bare_src => examples/example0}/include/test.h (100%) create mode 100644 conts/examples/example0/main.c rename conts/{bare_src => examples/example0}/src/test.c (100%) create mode 100644 conts/examples/example1/SConstruct create mode 100644 conts/examples/example1/container.c rename conts/{bare_src => examples/example1}/hello.c (100%) rename scripts/bare/__init__.py => conts/examples/example1/include/test.h (100%) rename conts/{bare_src => examples/example1}/main.c (100%) rename scripts/bare/files/SConstruct.in => conts/examples/example1/src/test.c (100%) create mode 100644 scripts/examples/__init__.py rename scripts/{bare/bare_generator.py => examples/examples_generator.py} (78%) create mode 100644 scripts/examples/files/SConstruct.in rename scripts/{bare => examples}/files/build.readme.in (100%) rename scripts/{bare => examples}/files/container.desc.in (100%) rename scripts/{bare => examples}/files/container.h.in (100%) rename scripts/{bare => examples}/files/linker.lds.in (100%) diff --git a/config/cml/container_ruleset.template b/config/cml/container_ruleset.template index 67e55fd..d06580f 100644 --- a/config/cml/container_ruleset.template +++ b/config/cml/container_ruleset.template @@ -1,6 +1,6 @@ symbols CONT%(cn)d_TYPE_LINUX 'Linux Container' -CONT%(cn)d_TYPE_BARE 'Bare Container' +CONT%(cn)d_TYPE_EXAMPLES 'Examples Container' CONT%(cn)d_TYPE_POSIX 'Codezero POSIX Services' CONT%(cn)d_TYPE_TEST 'Test Container' CONT%(cn)d_OPT_NAME 'Container Name' @@ -113,12 +113,12 @@ default CONT%(cn)d_VIRT4_END from 0x0 default CONT%(cn)d_VIRT5_START from 0x0 default CONT%(cn)d_VIRT5_END from 0x0 -default CONT%(cn)d_OPT_NAME from (CONT%(cn)d_TYPE_LINUX==y) ? "linux%(cn)d" : ((CONT%(cn)d_TYPE_BARE==y) ? "bare%(cn)d" : ((CONT%(cn)d_TYPE_TEST==y) ? "test%(cn)d" : "posix%(cn)d")) +default CONT%(cn)d_OPT_NAME from (CONT%(cn)d_TYPE_LINUX==y) ? "linux%(cn)d" : ((CONT%(cn)d_TYPE_EXAMPLES==y) ? "example%(cn)d" : ((CONT%(cn)d_TYPE_TEST==y) ? "test%(cn)d" : "posix%(cn)d")) -when CONT%(cn)d_TYPE_LINUX==y suppress cont%(cn)d_bare_pager_params cont%(cn)d_posix_pager_params -when CONT%(cn)d_TYPE_BARE==y suppress cont%(cn)d_linux_pager_params cont%(cn)d_posix_pager_params -when CONT%(cn)d_TYPE_TEST==y suppress cont%(cn)d_linux_pager_params cont%(cn)d_posix_pager_params -when CONT%(cn)d_TYPE_POSIX==y suppress cont%(cn)d_linux_pager_params +when CONT%(cn)d_TYPE_LINUX==y suppress cont%(cn)d_default_pager_params cont%(cn)d_posix_pager_params cont%(cn)d_examples_params +when CONT%(cn)d_TYPE_EXAMPLES==y suppress cont%(cn)d_linux_pager_params cont%(cn)d_posix_pager_params +when CONT%(cn)d_TYPE_TEST==y suppress cont%(cn)d_linux_pager_params cont%(cn)d_posix_pager_params cont%(cn)d_examples_params +when CONT%(cn)d_TYPE_POSIX==y suppress cont%(cn)d_linux_pager_params cont%(cn)d_examples_params symbols cont%(cn)d_menu 'Container %(cn)d Parameters' @@ -128,10 +128,20 @@ container%(cn)d_type 'Container %(cn)d Type' container%(cn)d_options 'Container %(cn)d Options' cont%(cn)d_linux_pager_params 'Container %(cn)d Linux Pager Parameters' -cont%(cn)d_bare_pager_params 'Container %(cn)d Default Pager Parameters' +cont%(cn)d_default_pager_params 'Container %(cn)d Default Pager Parameters' cont%(cn)d_posix_pager_params 'Container %(cn)d POSIX Pager Parameters' -menu cont%(cn)d_bare_pager_params +cont%(cn)d_examples_params 'Example Applications List' +CONT%(cn)d_EXAMPLE_APP0 'Empty Application' +CONT%(cn)d_EXAMPLE_APP1 'Hello world' + + +choices cont%(cn)d_examples_params + CONT%(cn)d_EXAMPLE_APP0 + CONT%(cn)d_EXAMPLE_APP1 + default CONT%(cn)d_EXAMPLE_APP0 + +menu cont%(cn)d_default_pager_params CONT%(cn)d_PAGER_LMA@ CONT%(cn)d_PAGER_VMA@ @@ -178,20 +188,20 @@ menu cont%(cn)d_physmem_list menu container%(cn)d_options CONT%(cn)d_OPT_NAME$ + cont%(cn)d_examples_params cont%(cn)d_linux_pager_params - cont%(cn)d_bare_pager_params + cont%(cn)d_default_pager_params cont%(cn)d_posix_pager_params cont%(cn)d_physmem_list cont%(cn)d_virtmem_list choices container%(cn)d_type CONT%(cn)d_TYPE_LINUX - CONT%(cn)d_TYPE_BARE + CONT%(cn)d_TYPE_EXAMPLES CONT%(cn)d_TYPE_POSIX CONT%(cn)d_TYPE_TEST - default CONT%(cn)d_TYPE_BARE + default CONT%(cn)d_TYPE_EXAMPLES menu cont%(cn)d_menu container%(cn)d_type container%(cn)d_options - diff --git a/config/configuration.py b/config/configuration.py index 0e9bf59..6c0de05 100644 --- a/config/configuration.py +++ b/config/configuration.py @@ -10,6 +10,7 @@ class Container: self.name = None self.type = None self.id = id + self.example_id = 0 self.pager_lma = 0 self.pager_vma = 0 self.pager_size = 0 @@ -167,6 +168,9 @@ class configuration: dirname = val[1:-1].lower() self.containers[id].dirname = dirname self.containers[id].name = dirname + elif param[:len("EXAMPLE_APP")] == "EXAMPLE_APP": + param1 = param.split("_", 1) + self.containers[id].example_id = param1[1][-1:] else: param1, param2 = param.split("_", 1) if param1 == "TYPE": @@ -174,11 +178,10 @@ class configuration: self.containers[id].type = "linux" elif param2 == "POSIX": self.containers[id].type = "posix" - elif param2 == "BARE": - self.containers[id].type = "bare" + elif param2 == "EXAMPLES": + self.containers[id].type = "examples" elif param2 == "TEST": self.containers[id].type = "test" - # Extract parameters for containers def get_container_parameters(self, name, val): matchobj = re.match(r"(CONFIG_CONT){1}([0-9]){1}(\w+)", name) diff --git a/configure.py b/configure.py index 28d75d6..617bfa0 100755 --- a/configure.py +++ b/configure.py @@ -4,7 +4,7 @@ import os, sys, shelve, shutil from os.path import join from config.projpaths import * from config.configuration import * -from scripts.bare.bare_generator import * +from scripts.examples.examples_generator import * from scripts.kernel.generate_kernel_cinfo import * from scripts.cml.generate_container_cml import * from optparse import OptionParser @@ -185,9 +185,9 @@ def configure_system(options, args): configuration_save(config) - # Generate bare container files if new ones defined - bare_cont_gen = BareContGenerator() - bare_cont_gen.bare_container_generate(config) + # Generate example container files if new ones defined + examples_cont_gen = ExamplesContGenerator() + examples_cont_gen.examples_container_generate(config) # Print out the configuration if asked if options.print_config: diff --git a/conts/bare_src/SConstruct b/conts/examples/example0/SConstruct similarity index 53% rename from conts/bare_src/SConstruct rename to conts/examples/example0/SConstruct index 3bd1575..23e059c 100644 --- a/conts/bare_src/SConstruct +++ b/conts/examples/example0/SConstruct @@ -13,45 +13,39 @@ sys.path.append(PROJRELROOT) from config.projpaths import * from config.configuration import * -from configure import * + config = configuration_retrieve() -arch = config.arch -gcc_cpu_flag = config.gcc_cpu_flag -# Wrapper library for system calls +arch = config.arch + LIBL4_RELDIR = 'conts/libl4' KERNEL_INCLUDE = join(PROJROOT, 'include') LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR) LIBL4_INCLUDE = join(LIBL4_DIR, 'include') LIBL4_LIBPATH = join(BUILDDIR, LIBL4_RELDIR) -# Some user-space libraries +# Locally important paths are here LIBC_RELDIR = 'conts/libc' LIBC_DIR = join(PROJROOT, LIBC_RELDIR) LIBC_LIBPATH = join(BUILDDIR, LIBC_RELDIR) LIBC_INCLUDE = [join(LIBC_DIR, 'include'), \ join(LIBC_DIR, 'include/arch' + '/' + arch)] -LIBMEM_RELDIR = 'conts/libmem' -LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR) -LIBMEM_LIBPATH = join(BUILDDIR, LIBMEM_RELDIR) -LIBMEM_INCLUDE = LIBMEM_DIR -env = Environment(CC = config.user_toolchain + 'gcc', +env = Environment(CC = 'arm-none-linux-gnueabi-gcc', # We don't use -nostdinc because sometimes we need standard headers, # such as stdarg.h e.g. for variable args, as in printk(). - CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', \ - '-Werror', ('-mcpu=' + gcc_cpu_flag)], \ + CCFLAGS = ['-g', '-mcpu=arm926ej-s', '-nostdlib', '-ffreestanding', \ + '-std=gnu99', '-Wall', '-Werror'], \ LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"],\ ASFLAGS = ['-D__ASSEMBLY__'], \ - PROGSUFFIX = '.elf', # The suffix to use for final executable - ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path - LIBS = ['gcc', 'libl4', 'c-userspace', 'libmm', 'libmc', 'libmalloc', \ - 'gcc', 'c-userspace'], # libgcc.a - This is required for division routines. - CPPPATH = ["#include", KERNEL_INCLUDE, LIBL4_INCLUDE, LIBC_INCLUDE, LIBMEM_INCLUDE], - LIBPATH = [LIBL4_LIBPATH, LIBC_LIBPATH, LIBMEM_LIBPATH], - CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h') + PROGSUFFIX = '.elf', # The suffix to use for final executable\ + ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path\ + LIBS = ['gcc', 'libl4', 'c-userspace', 'gcc', 'c-userspace'], # libgcc.a - This is required for division routines. + CPPPATH = ["#include", KERNEL_INCLUDE, LIBL4_INCLUDE, LIBC_INCLUDE], + LIBPATH = [LIBL4_LIBPATH, LIBC_LIBPATH], + CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h') src = Glob('*.[cS]') src += Glob('src/*.[cS]') diff --git a/conts/bare_src/container.c b/conts/examples/example0/container.c similarity index 91% rename from conts/bare_src/container.c rename to conts/examples/example0/container.c index 7bcbf9e..f570c3d 100644 --- a/conts/bare_src/container.c +++ b/conts/examples/example0/container.c @@ -8,7 +8,7 @@ #include -void main(void); +extern void main(void); void __container_init(void) { diff --git a/conts/bare_src/include/test.h b/conts/examples/example0/include/test.h similarity index 100% rename from conts/bare_src/include/test.h rename to conts/examples/example0/include/test.h diff --git a/conts/examples/example0/main.c b/conts/examples/example0/main.c new file mode 100644 index 0000000..8397a52 --- /dev/null +++ b/conts/examples/example0/main.c @@ -0,0 +1,12 @@ +/* + * Main function for this container + */ +#include +#include +#include + +int main(void) +{ + return 0; +} + diff --git a/conts/bare_src/src/test.c b/conts/examples/example0/src/test.c similarity index 100% rename from conts/bare_src/src/test.c rename to conts/examples/example0/src/test.c diff --git a/conts/examples/example1/SConstruct b/conts/examples/example1/SConstruct new file mode 100644 index 0000000..23e059c --- /dev/null +++ b/conts/examples/example1/SConstruct @@ -0,0 +1,55 @@ +# -*- mode: python; coding: utf-8; -*- +# +# Codezero -- Virtualization microkernel for embedded systems. +# +# Copyright © 2009 B Labs Ltd +# +import os, shelve, sys +from os.path import * + +PROJRELROOT = '../..' + +sys.path.append(PROJRELROOT) + +from config.projpaths import * +from config.configuration import * + + +config = configuration_retrieve() + +arch = config.arch + +LIBL4_RELDIR = 'conts/libl4' +KERNEL_INCLUDE = join(PROJROOT, 'include') +LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR) +LIBL4_INCLUDE = join(LIBL4_DIR, 'include') +LIBL4_LIBPATH = join(BUILDDIR, LIBL4_RELDIR) + +# Locally important paths are here +LIBC_RELDIR = 'conts/libc' +LIBC_DIR = join(PROJROOT, LIBC_RELDIR) +LIBC_LIBPATH = join(BUILDDIR, LIBC_RELDIR) +LIBC_INCLUDE = [join(LIBC_DIR, 'include'), \ + join(LIBC_DIR, 'include/arch' + '/' + arch)] + + +env = Environment(CC = 'arm-none-linux-gnueabi-gcc', + # We don't use -nostdinc because sometimes we need standard headers, + # such as stdarg.h e.g. for variable args, as in printk(). + CCFLAGS = ['-g', '-mcpu=arm926ej-s', '-nostdlib', '-ffreestanding', \ + '-std=gnu99', '-Wall', '-Werror'], \ + LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"],\ + ASFLAGS = ['-D__ASSEMBLY__'], \ + PROGSUFFIX = '.elf', # The suffix to use for final executable\ + ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path\ + LIBS = ['gcc', 'libl4', 'c-userspace', 'gcc', 'c-userspace'], # libgcc.a - This is required for division routines. + CPPPATH = ["#include", KERNEL_INCLUDE, LIBL4_INCLUDE, LIBC_INCLUDE], + LIBPATH = [LIBL4_LIBPATH, LIBC_LIBPATH], + CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h') + +src = Glob('*.[cS]') +src += Glob('src/*.[cS]') + +objs = env.Object(src) +prog = env.Program('main.elf', objs) +Depends(prog, 'include/linker.lds') diff --git a/conts/examples/example1/container.c b/conts/examples/example1/container.c new file mode 100644 index 0000000..f570c3d --- /dev/null +++ b/conts/examples/example1/container.c @@ -0,0 +1,21 @@ +/* + * Container entry point for pager + * + * Copyright (C) 2007-2009 B Labs Ltd. + */ + +#include +#include + + +extern void main(void); + +void __container_init(void) +{ + /* Generic L4 initialisation */ + __l4_init(); + + /* Entry to main */ + main(); +} + diff --git a/conts/bare_src/hello.c b/conts/examples/example1/hello.c similarity index 100% rename from conts/bare_src/hello.c rename to conts/examples/example1/hello.c diff --git a/scripts/bare/__init__.py b/conts/examples/example1/include/test.h similarity index 100% rename from scripts/bare/__init__.py rename to conts/examples/example1/include/test.h diff --git a/conts/bare_src/main.c b/conts/examples/example1/main.c similarity index 100% rename from conts/bare_src/main.c rename to conts/examples/example1/main.c diff --git a/scripts/bare/files/SConstruct.in b/conts/examples/example1/src/test.c similarity index 100% rename from scripts/bare/files/SConstruct.in rename to conts/examples/example1/src/test.c diff --git a/scripts/conts/containers.py b/scripts/conts/containers.py index 4514880..a0cb77f 100755 --- a/scripts/conts/containers.py +++ b/scripts/conts/containers.py @@ -55,7 +55,7 @@ def source_to_builddir(srcdir, id): return join(BUILDDIR, cont_builddir) # We simply use SCons to figure all this out from container.id -# This is very similar to default container builder: +# This is very similar to examples container builder: # In fact this notion may become a standard convention for # calling specific bare containers def build_posix_container(config, projpaths, container): @@ -110,7 +110,7 @@ def build_default_container(config, projpaths, container): os.path.walk(projdir, glob_by_walk, ['*.elf', images]) # Calculate and store size of pager - pager_binary = "conts/bare" + str(container.id) + "/main.elf" + pager_binary = "conts/example" + str(container.id) + "/main.elf" config.containers[container.id].pager_size = \ conv_hex(elf_binary_size(join(PROJROOT, pager_binary))) @@ -124,7 +124,7 @@ def build_all_containers(): if container.type == 'linux': pass cont_images.append(build_linux_container(config, projpaths, container)) - elif container.type == 'bare': + elif container.type == 'examples': cont_images.append(build_default_container(config, projpaths, container)) elif container.type == 'posix': cont_images.append(build_posix_container(config, projpaths, container)) diff --git a/scripts/examples/__init__.py b/scripts/examples/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scripts/bare/bare_generator.py b/scripts/examples/examples_generator.py similarity index 78% rename from scripts/bare/bare_generator.py rename to scripts/examples/examples_generator.py index 3c6f1c2..17663d7 100755 --- a/scripts/bare/bare_generator.py +++ b/scripts/examples/examples_generator.py @@ -19,11 +19,11 @@ from config.projpaths import * from config.configuration import * from config.lib import * -class BareContGenerator: +class ExamplesContGenerator: def __init__(self): self.CONT_SRC_DIR = '' # Set when container is selected - self.BARE_SRC_BASEDIR = join(PROJROOT, 'conts') - self.EXAMPLE_PROJ_SRC_DIR = join(PROJROOT, 'conts/bare_src') + self.EXAMPLES_SRC_BASEDIR = join(PROJROOT, 'conts') + self.EXAMPLES_PROJ_SRC_DIR = join(PROJROOT, 'conts/examples') self.main_builder_name = 'build.py' self.main_configurator_name = 'configure.py' @@ -47,11 +47,12 @@ class BareContGenerator: self.build_desc_out = None self.src_main_out = None - def create_bare_srctree(self, config, cont): + def create_examples_srctree(self, config, cont): # First, create the base project directory and sources - shutil.copytree(self.EXAMPLE_PROJ_SRC_DIR, self.CONT_SRC_DIR) + str = 'example' + cont.example_id + shutil.copytree(join(self.EXAMPLES_PROJ_SRC_DIR, str), self.CONT_SRC_DIR) - def copy_bare_build_desc(self, config, cont): + def copy_examples_build_desc(self, config, cont): id_header = '[Container ID]\n' type_header = '\n[Container Type]\n' name_header = '\n[Container Name]\n' @@ -78,7 +79,7 @@ class BareContGenerator: fout.write(pager_physmem_header % ireg) fout.write('\t' + cont.physmem["START"][ireg] + ' - ' + cont.physmem["END"][ireg] + '\n') - def copy_bare_build_readme(self, config, cont): + def copy_examples_build_readme(self, config, cont): with open(self.build_readme_in) as fin: str = fin.read() with open(self.build_readme_out, 'w+') as fout: @@ -90,30 +91,30 @@ class BareContGenerator: self.main_configurator_name, \ self.main_configurator_name)) - def copy_bare_container_h(self, config, cont): + def copy_examples_container_h(self, config, cont): with open(self.container_h_in) as fin: str = fin.read() with open(self.container_h_out, 'w+') as fout: # Make any manipulations here fout.write(str % (cont.name, cont.id, cont.id)) - def create_bare_sources(self, config, cont): - self.create_bare_srctree(config, cont) - self.copy_bare_build_readme(config, cont) - self.copy_bare_build_desc(config, cont) + def create_examples_sources(self, config, cont): + self.create_examples_srctree(config, cont) + self.copy_examples_build_readme(config, cont) + self.copy_examples_build_desc(config, cont) self.generate_linker_script(config, cont) - self.copy_bare_container_h(config, cont) + self.copy_examples_container_h(config, cont) def update_configuration(self, config, cont): - self.copy_bare_build_desc(config, cont) + self.copy_examples_build_desc(config, cont) self.generate_linker_script(config, cont) - self.copy_bare_container_h(config, cont) + self.copy_examples_container_h(config, cont) - def check_create_bare_sources(self, config): + def check_create_examples_sources(self, config): for cont in config.containers: - if cont.type == "bare": + if cont.type == "examples": # Determine container directory name. - self.CONT_SRC_DIR = join(self.BARE_SRC_BASEDIR, cont.dirname.lower()) + self.CONT_SRC_DIR = join(self.EXAMPLES_SRC_BASEDIR, cont.dirname.lower()) self.build_readme_out = join(self.CONT_SRC_DIR, self.build_readme_name) self.build_desc_out = join(self.CONT_SRC_DIR, self.build_desc_name) self.linker_lds_out = join(join(self.CONT_SRC_DIR, 'include'), \ @@ -121,8 +122,8 @@ class BareContGenerator: self.container_h_out = join(join(self.CONT_SRC_DIR, 'include'), \ self.container_h_name) - if not os.path.exists(join(self.BARE_SRC_BASEDIR, cont.dirname)): - self.create_bare_sources(config, cont) + if not os.path.exists(join(self.EXAMPLES_SRC_BASEDIR, cont.dirname)): + self.create_examples_sources(config, cont) else: # Don't create new sources but update configuration self.update_configuration(config, cont) @@ -134,12 +135,12 @@ class BareContGenerator: fout.write(str % (conv_hex(cont.pager_vma), \ conv_hex(cont.pager_lma))) - def bare_container_generate(self, config): - self.check_create_bare_sources(config) + def examples_container_generate(self, config): + self.check_create_examples_sources(config) if __name__ == "__main__": config = configuration_retrieve() config.config_print() - bare_cont = BareContGenerator() - bare_cont.bare_container_generate(config) + examples_cont = ExamplesContGenerator() + examples_cont.examples_container_generate(config) diff --git a/scripts/examples/files/SConstruct.in b/scripts/examples/files/SConstruct.in new file mode 100644 index 0000000..e69de29 diff --git a/scripts/bare/files/build.readme.in b/scripts/examples/files/build.readme.in similarity index 100% rename from scripts/bare/files/build.readme.in rename to scripts/examples/files/build.readme.in diff --git a/scripts/bare/files/container.desc.in b/scripts/examples/files/container.desc.in similarity index 100% rename from scripts/bare/files/container.desc.in rename to scripts/examples/files/container.desc.in diff --git a/scripts/bare/files/container.h.in b/scripts/examples/files/container.h.in similarity index 100% rename from scripts/bare/files/container.h.in rename to scripts/examples/files/container.h.in diff --git a/scripts/bare/files/linker.lds.in b/scripts/examples/files/linker.lds.in similarity index 100% rename from scripts/bare/files/linker.lds.in rename to scripts/examples/files/linker.lds.in From 69a09ea514e34abb413706562b9078212df97f5b Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Thu, 5 Nov 2009 11:32:02 +0200 Subject: [PATCH 03/19] Automatic pager size calculation takes container name into account instead of a fixed one. --- scripts/conts/containers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/conts/containers.py b/scripts/conts/containers.py index a0cb77f..f42bca9 100755 --- a/scripts/conts/containers.py +++ b/scripts/conts/containers.py @@ -110,7 +110,7 @@ def build_default_container(config, projpaths, container): os.path.walk(projdir, glob_by_walk, ['*.elf', images]) # Calculate and store size of pager - pager_binary = "conts/example" + str(container.id) + "/main.elf" + pager_binary = "conts/" + container.name + "/main.elf" config.containers[container.id].pager_size = \ conv_hex(elf_binary_size(join(PROJROOT, pager_binary))) From 00adcd9afaafdafb57d2d371b52cfe94dcce206a Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Thu, 29 Oct 2009 22:00:38 +0200 Subject: [PATCH 04/19] libl4thread skeleton is introduced. With this library, it is aimed at easing thread manipulation, utcb handling etc. --- SConstruct.userlibs | 4 ++++ conts/libl4thread/SConscript | 25 +++++++++++++++++++++ conts/libl4thread/include/l4thread/thread.h | 9 ++++++++ conts/libl4thread/src/thread.c | 10 +++++++++ 4 files changed, 48 insertions(+) create mode 100644 conts/libl4thread/SConscript create mode 100644 conts/libl4thread/include/l4thread/thread.h create mode 100644 conts/libl4thread/src/thread.c diff --git a/SConstruct.userlibs b/SConstruct.userlibs index 330883b..599b814 100644 --- a/SConstruct.userlibs +++ b/SConstruct.userlibs @@ -44,9 +44,13 @@ libmm, libmc, libmalloc = SConscript('conts/libmem/SConscript', \ duplicate = 0, variant_dir = \ join(BUILDDIR, os.path.relpath('conts/libmem', PROJROOT))) +libl4thread = SConscript('conts/libl4thread/SConscript', \ + exports = { 'env' : env }, duplicate = 0, \ + variant_dir = join(BUILDDIR, os.path.relpath('conts/libl4thread', PROJROOT))) Alias('libl4', libl4) Alias('libc', libc) Alias('libmm', libmm) Alias('libmc', libmc) Alias('libmalloc', libmalloc) +Alias('libl4thread', libl4thread) diff --git a/conts/libl4thread/SConscript b/conts/libl4thread/SConscript new file mode 100644 index 0000000..2ca1bf8 --- /dev/null +++ b/conts/libl4thread/SConscript @@ -0,0 +1,25 @@ +# -*- mode: python; coding: utf-8; -*- +# +# Codezero -- Virtualization microkernel for embedded systems. +# +# Copyright © 2009 B Labs Ltd + +import os, sys + +# Get global paths +PROJRELROOT = '../..' + +sys.path.append(PROJRELROOT) + +from config.projpaths import * + +Import('env') + +e = env.Clone() +e.Append(CPPPATH = ['include/l4thread']) + +source = [Glob('*.[cS]') + Glob('src/*.[cS]')] +objects = e.StaticObject(source) +library = e.StaticLibrary('l4thread', objects) + +Return('library') diff --git a/conts/libl4thread/include/l4thread/thread.h b/conts/libl4thread/include/l4thread/thread.h new file mode 100644 index 0000000..31ced16 --- /dev/null +++ b/conts/libl4thread/include/l4thread/thread.h @@ -0,0 +1,9 @@ +/* + * + */ +#ifndef __LIB_THREAD_H__ +#define __LIB_THREAD_H__ + +void l4thread_print(void); + +#endif /* __LIB_THREAD_H__ */ diff --git a/conts/libl4thread/src/thread.c b/conts/libl4thread/src/thread.c new file mode 100644 index 0000000..21b574a --- /dev/null +++ b/conts/libl4thread/src/thread.c @@ -0,0 +1,10 @@ +/* + * + */ + +#include + +void l4thread_print(void) +{ + printf("Hello world from libl4thread!\n"); +} From 18a5c89c972007860134bfe687a6efce8dbca585 Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Thu, 29 Oct 2009 22:11:49 +0200 Subject: [PATCH 05/19] utcb handling helper routines for the thread library. This is one of the steps we need in the process of providing a similar interface for thread creation which can be found in the mainstream operating systems like Linux. --- conts/libl4thread/SConscript | 5 +- conts/libl4thread/include/l4thread/addr.h | 26 +++++ conts/libl4thread/include/l4thread/bit.h | 42 ++++++++ conts/libl4thread/include/l4thread/idpool.h | 30 ++++++ conts/libl4thread/include/l4thread/utcb.h | 25 +++++ conts/libl4thread/src/addr.c | 55 ++++++++++ conts/libl4thread/src/bit.c | 109 ++++++++++++++++++++ conts/libl4thread/src/idpool.c | 86 +++++++++++++++ conts/libl4thread/src/thread.c | 3 +- conts/libl4thread/src/utcb.c | 88 ++++++++++++++++ conts/libl4thread/src/utcb_test.c | 55 ++++++++++ 11 files changed, 522 insertions(+), 2 deletions(-) create mode 100644 conts/libl4thread/include/l4thread/addr.h create mode 100644 conts/libl4thread/include/l4thread/bit.h create mode 100644 conts/libl4thread/include/l4thread/idpool.h create mode 100644 conts/libl4thread/include/l4thread/utcb.h create mode 100644 conts/libl4thread/src/addr.c create mode 100644 conts/libl4thread/src/bit.c create mode 100644 conts/libl4thread/src/idpool.c create mode 100644 conts/libl4thread/src/utcb.c create mode 100644 conts/libl4thread/src/utcb_test.c diff --git a/conts/libl4thread/SConscript b/conts/libl4thread/SConscript index 2ca1bf8..876bf5c 100644 --- a/conts/libl4thread/SConscript +++ b/conts/libl4thread/SConscript @@ -15,8 +15,11 @@ from config.projpaths import * Import('env') +LIBMEM_RELDIR = 'conts/libmem' +LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR) + e = env.Clone() -e.Append(CPPPATH = ['include/l4thread']) +e.Append(CPPPATH = ['include/l4thread', LIBMEM_DIR]) source = [Glob('*.[cS]') + Glob('src/*.[cS]')] objects = e.StaticObject(source) diff --git a/conts/libl4thread/include/l4thread/addr.h b/conts/libl4thread/include/l4thread/addr.h new file mode 100644 index 0000000..5bbc69d --- /dev/null +++ b/conts/libl4thread/include/l4thread/addr.h @@ -0,0 +1,26 @@ +/* + * Address allocation pool + * + * Copyright (C) 2007 Bahadir Balban + */ +#ifndef __ADDR_H__ +#define __ADDR_H__ + +#include + +/* Address pool to allocate from a range of addresses */ +struct address_pool { + struct id_pool *idpool; + unsigned long start; + unsigned long end; +}; + +int address_pool_init_with_idpool(struct address_pool *pool, + struct id_pool *idpool, + unsigned long start, unsigned long end); +int address_pool_init(struct address_pool *pool, unsigned long start, + unsigned long end); +void *address_new(struct address_pool *pool, int npages); +int address_del(struct address_pool *, void *addr, int npages); + +#endif /* __ADDR_H__ */ diff --git a/conts/libl4thread/include/l4thread/bit.h b/conts/libl4thread/include/l4thread/bit.h new file mode 100644 index 0000000..3ab6822 --- /dev/null +++ b/conts/libl4thread/include/l4thread/bit.h @@ -0,0 +1,42 @@ +#ifndef __BIT_H__ +#define __BIT_H__ + +unsigned int __clz(unsigned int bitvector); +int find_and_set_first_free_bit(u32 *word, unsigned int lastbit); +int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit, + int nbits); +int check_and_clear_bit(u32 *word, int bit); +int check_and_clear_contig_bits(u32 *word, int first, int nbits); + +int check_and_set_bit(u32 *word, int bit); + +/* Set */ +static inline void setbit(unsigned int *w, unsigned int flags) +{ + *w |= flags; +} + + +/* Clear */ +static inline void clrbit(unsigned int *w, unsigned int flags) +{ + *w &= ~flags; +} + +/* Test */ +static inline int tstbit(unsigned int *w, unsigned int flags) +{ + return *w & flags; +} + +/* Test and clear */ +static inline int tstclr(unsigned int *w, unsigned int flags) +{ + int res = tstbit(w, flags); + + clrbit(w, flags); + + return res; +} + +#endif /* __BIT_H__ */ diff --git a/conts/libl4thread/include/l4thread/idpool.h b/conts/libl4thread/include/l4thread/idpool.h new file mode 100644 index 0000000..67667c2 --- /dev/null +++ b/conts/libl4thread/include/l4thread/idpool.h @@ -0,0 +1,30 @@ +#ifndef __IDPOOL_H__ +#define __IDPOOL_H__ + +#include +#include +#include INC_GLUE(memory.h) + +struct id_pool { + int nwords; + int bitlimit; + u32 bitmap[]; +}; + +/* Copy one id pool to another by calculating its size */ +static inline void id_pool_copy(struct id_pool *to, struct id_pool *from, int totalbits) +{ + int nwords = BITWISE_GETWORD(totalbits); + + memcpy(to, from, nwords * SZ_WORD + sizeof(struct id_pool)); +} + +struct id_pool *id_pool_new_init(int mapsize); +int id_new(struct id_pool *pool); +int id_del(struct id_pool *pool, int id); +int id_get(struct id_pool *pool, int id); +int id_is_empty(struct id_pool *pool); +int ids_new_contiguous(struct id_pool *pool, int numids); +int ids_del_contiguous(struct id_pool *pool, int first, int numids); + +#endif /* __IDPOOL_H__ */ diff --git a/conts/libl4thread/include/l4thread/utcb.h b/conts/libl4thread/include/l4thread/utcb.h new file mode 100644 index 0000000..464bd45 --- /dev/null +++ b/conts/libl4thread/include/l4thread/utcb.h @@ -0,0 +1,25 @@ +/* + * UTCB handling helper routines + * + * Copyright (C) 2009 B Labs Ltd. + */ +#ifndef __UTCB_H__ +#define __UTCB_H__ + +#include + +struct utcb_desc { + struct link list; + unsigned long utcb_base; + struct id_pool *slots; +}; + +int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end); + +unsigned long utcb_new_slot(struct utcb_desc *desc); +int utcb_delete_slot(struct utcb_desc *desc, unsigned long address); + +struct utcb_desc *utcb_new_desc(void); +int utcb_delete_desc(struct utcb_desc *desc); + +#endif /* __UTCB_H__ */ diff --git a/conts/libl4thread/src/addr.c b/conts/libl4thread/src/addr.c new file mode 100644 index 0000000..10206bd --- /dev/null +++ b/conts/libl4thread/src/addr.c @@ -0,0 +1,55 @@ +/* + * This module allocates an unused address range from + * a given memory region defined as the pool range. + * + * Copyright (C) 2007 Bahadir Balban + */ +#include +#include + +/* + * Initializes an address pool, but uses an already + * allocated id pool for it. + */ +int address_pool_init_with_idpool(struct address_pool *pool, + struct id_pool *idpool, + unsigned long start, unsigned long end) +{ + pool->idpool = idpool; + pool->start = start; + pool->end = end; + + return 0; +} + +int address_pool_init(struct address_pool *pool, unsigned long start, unsigned long end) +{ + if ((pool->idpool = id_pool_new_init(__pfn(end - start))) < 0) + return (int)pool->idpool; + pool->start = start; + pool->end = end; + return 0; +} + +void *address_new(struct address_pool *pool, int npages) +{ + unsigned int pfn; + + if ((int)(pfn = ids_new_contiguous(pool->idpool, npages)) < 0) + return 0; + + return (void *)__pfn_to_addr(pfn) + pool->start; +} + +int address_del(struct address_pool *pool, void *addr, int npages) +{ + unsigned long pfn = __pfn(page_align(addr) - pool->start); + + if (ids_del_contiguous(pool->idpool, pfn, npages) < 0) { + printf("%s: Invalid address range returned to " + "virtual address pool.\n", __FUNCTION__); + return -1; + } + return 0; +} + diff --git a/conts/libl4thread/src/bit.c b/conts/libl4thread/src/bit.c new file mode 100644 index 0000000..b021211 --- /dev/null +++ b/conts/libl4thread/src/bit.c @@ -0,0 +1,109 @@ +/* + * Bit manipulation functions. + * + * Copyright (C) 2007 Bahadir Balban + */ +#include +#include +#include INC_GLUE(memory.h) + +/* Emulation of ARM's CLZ (count leading zeroes) instruction */ +unsigned int __clz(unsigned int bitvector) +{ + unsigned int x = 0; + while((!(bitvector & ((unsigned)1 << 31))) && (x < 32)) { + bitvector <<= 1; + x++; + } + return x; +} + +int find_and_set_first_free_bit(u32 *word, unsigned int limit) +{ + int success = 0; + int i; + + for(i = 0; i < limit; i++) { + /* Find first unset bit */ + if (!(word[BITWISE_GETWORD(i)] & BITWISE_GETBIT(i))) { + /* Set it */ + word[BITWISE_GETWORD(i)] |= BITWISE_GETBIT(i); + success = 1; + break; + } + } + /* Return bit just set */ + if (success) + return i; + else + return -1; +} + +int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit, + int nbits) +{ + int i = 0, first = 0, last = 0, found = 0; + + /* Can't allocate more than the limit */ + if (nbits > limit) + return -1; + + /* This is a state machine that checks n contiguous free bits. */ + /* FIXME: It should be <= instead of <. Fix & test in a single patch */ + while (i + nbits < limit) { + first = i; + last = i; + while (!(word[BITWISE_GETWORD(last)] & BITWISE_GETBIT(last))) { + last++; + i++; + if (last == first + nbits) { + found = 1; + break; + } + } + if (found) + break; + i++; + } + + /* If found, set the bits */ + if (found) { + for (int x = first; x < first + nbits; x++) + word[BITWISE_GETWORD(x)] |= BITWISE_GETBIT(x); + return first; + } else + return -1; +} + +int check_and_clear_bit(u32 *word, int bit) +{ + /* Check that bit was set */ + if (word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit)) { + word[BITWISE_GETWORD(bit)] &= ~BITWISE_GETBIT(bit); + return 0; + } else { + printf("Trying to clear already clear bit\n"); + return -1; + } +} + +int check_and_set_bit(u32 *word, int bit) +{ + /* Check that bit was clear */ + if (!(word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit))) { + word[BITWISE_GETWORD(bit)] |= BITWISE_GETBIT(bit); + return 0; + } else { + //printf("Trying to set already set bit\n"); + return -1; + } +} + +int check_and_clear_contig_bits(u32 *word, int first, int nbits) +{ + for (int i = first; i < first + nbits; i++) + if (check_and_clear_bit(word, i) < 0) + return -1; + return 0; +} + diff --git a/conts/libl4thread/src/idpool.c b/conts/libl4thread/src/idpool.c new file mode 100644 index 0000000..423ac33 --- /dev/null +++ b/conts/libl4thread/src/idpool.c @@ -0,0 +1,86 @@ +/* + * Used for thread and space ids, and also for utcbs. + * + * 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/thread.c b/conts/libl4thread/src/thread.c index 21b574a..c362960 100644 --- a/conts/libl4thread/src/thread.c +++ b/conts/libl4thread/src/thread.c @@ -1,9 +1,10 @@ /* * */ - #include +extern void utcb_test(unsigned long utcb_start, unsigned long utcb_end); + void l4thread_print(void) { printf("Hello world from libl4thread!\n"); diff --git a/conts/libl4thread/src/utcb.c b/conts/libl4thread/src/utcb.c new file mode 100644 index 0000000..9dcc187 --- /dev/null +++ b/conts/libl4thread/src/utcb.c @@ -0,0 +1,88 @@ +/* + * UTCB management in Codezero + * + * Copyright © 2009 B Labs Ltd + */ +#include +#include +#include +#include + +/* Globally disjoint utcb virtual region pool */ +static struct address_pool utcb_region_pool; + +int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end) +{ + int err; + + /* Initialise the global utcb virtual address pool */ + if ((err = address_pool_init(&utcb_region_pool, + utcb_start, utcb_end) < 0)) { + printf("UTCB address pool initialisation failed.\n"); + return err; + } + + return 0; +} + +static inline void *utcb_new_address(int npages) +{ + return address_new(&utcb_region_pool, npages); +} + +static inline int utcb_delete_address(void *utcb_address, int npages) +{ + return address_del(&utcb_region_pool, utcb_address, npages); +} + +/* Return an empty utcb slot in this descriptor */ +unsigned long utcb_new_slot(struct utcb_desc *desc) +{ + int slot; + + if ((slot = id_new(desc->slots)) < 0) + return 0; + else + return desc->utcb_base + (unsigned long)slot * UTCB_SIZE; +} + +int utcb_delete_slot(struct utcb_desc *desc, unsigned long address) +{ + BUG_ON(id_del(desc->slots, (address - desc->utcb_base) + / UTCB_SIZE) < 0); + return 0; +} + +struct utcb_desc *utcb_new_desc(void) +{ + struct utcb_desc *d; + + /* Allocate a new descriptor */ + if (!(d = kzalloc(sizeof(*d)))) + return 0; + + link_init(&d->list); + + /* We currently assume UTCB is smaller than PAGE_SIZE */ + BUG_ON(UTCB_SIZE > PAGE_SIZE); + + /* Initialise utcb slots */ + d->slots = id_pool_new_init(PAGE_SIZE / UTCB_SIZE); + + /* Obtain a new and unique utcb base */ + /* FIXME: Use variable size than a page */ + d->utcb_base = (unsigned long)utcb_new_address(1); + + return d; +} + +int utcb_delete_desc(struct utcb_desc *desc) +{ + /* Return descriptor address */ + utcb_delete_address((void *)desc->utcb_base, 1); + + /* Free the descriptor */ + kfree(desc); + + return 0; +} diff --git a/conts/libl4thread/src/utcb_test.c b/conts/libl4thread/src/utcb_test.c new file mode 100644 index 0000000..b05b7ca --- /dev/null +++ b/conts/libl4thread/src/utcb_test.c @@ -0,0 +1,55 @@ +/* + * This is for testing utcb port from POSIX + */ +#include +#include + +void utcb_test(unsigned long utcb_start, unsigned long utcb_end) +{ + struct utcb_desc *udesc[20]; + unsigned long addr; + int idx = -1; + + printf("%s\n", __FUNCTION__); + + utcb_pool_init(utcb_start, utcb_end); + + // Test-1 + for (int i = 0; i < 10; i++) + udesc[++idx] = utcb_new_desc(); + for (int j = 0; j < 20; ++j) + addr = utcb_new_slot(udesc[idx]); + + // Test 2 + for (int i = 0; i < 3; i++) + udesc[++idx] = utcb_new_desc(); + for (int j = 0; j < 10; ++j) + addr = utcb_new_slot(udesc[idx]); + for (int j = 0; j < 8; j++) { + utcb_delete_slot(udesc[idx], addr); + addr -= 0x100; + } + for (int j = 0; j < 2; ++j) + addr = utcb_new_slot(udesc[idx]); + for (int j = 0; j < 4; j++) { + utcb_delete_slot(udesc[idx], addr); + addr -= 0x100; + } + // Test 3 + for (int i = 0; i < 7; i++) { + utcb_delete_desc(udesc[idx]); + --idx; + } + for (int j = 0; j < 4; ++j) + addr = utcb_new_slot(udesc[idx]); + for (int j = 0; j < 2; j++) { + utcb_delete_slot(udesc[idx], addr); + addr -= 0x100; + } + for (int i = 0; i < 3; i++) + udesc[++idx] = utcb_new_desc(); + for (int i = 0; i < 7; i++) { + utcb_delete_desc(udesc[idx]); + --idx; + } +} From b31ab82437693ee7ee5e5a73574f324b60606b75 Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Wed, 4 Nov 2009 20:48:59 +0200 Subject: [PATCH 06/19] The first step in creating a thread library. The difference between this thread library and the existing ones like pthreads is the necessity of informing the library about the address range of the stack and the l4 specific utcb. Utcb has not been supported yet. As for stack, there is also a drawback: library does not support mapping. In other words, the stack area in question has to be already mapped-in. Thus, for now we only support threads sharing their address spaces: TC_SHARE_SPACE. In this respect, it is very similar to pthreads. --- conts/libl4thread/SConscript | 10 +- conts/libl4thread/include/l4thread/thread.h | 12 +- conts/libl4thread/src/arch | 1 + conts/libl4thread/src/arch-arm/new_thread.S | 11 ++ conts/libl4thread/src/thread.c | 121 +++++++++++++++++++- conts/libl4thread/src/utcb_test.c | 55 --------- 6 files changed, 148 insertions(+), 62 deletions(-) create mode 120000 conts/libl4thread/src/arch create mode 100644 conts/libl4thread/src/arch-arm/new_thread.S delete mode 100644 conts/libl4thread/src/utcb_test.c diff --git a/conts/libl4thread/SConscript b/conts/libl4thread/SConscript index 876bf5c..abcda27 100644 --- a/conts/libl4thread/SConscript +++ b/conts/libl4thread/SConscript @@ -18,10 +18,14 @@ Import('env') LIBMEM_RELDIR = 'conts/libmem' LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR) -e = env.Clone() -e.Append(CPPPATH = ['include/l4thread', LIBMEM_DIR]) +LIBL4_RELDIR = 'conts/libl4' +LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR) +LIBL4_INCLUDE = join(LIBL4_DIR, 'include') -source = [Glob('*.[cS]') + Glob('src/*.[cS]')] +e = env.Clone() +e.Append(CPPPATH = ['include/l4thread', LIBMEM_DIR, LIBL4_INCLUDE]) + +source = [Glob('*.[cS]') + Glob('src/*.[cS]') + Glob('src/arch/*.[cS]')] objects = e.StaticObject(source) library = e.StaticLibrary('l4thread', objects) diff --git a/conts/libl4thread/include/l4thread/thread.h b/conts/libl4thread/include/l4thread/thread.h index 31ced16..658d17b 100644 --- a/conts/libl4thread/include/l4thread/thread.h +++ b/conts/libl4thread/include/l4thread/thread.h @@ -1,9 +1,19 @@ /* + * Thread creation userspace helpers * + * Copyright (C) 2009 B Labs Ltd. */ #ifndef __LIB_THREAD_H__ #define __LIB_THREAD_H__ -void l4thread_print(void); +#define STACK_TOP_ADDR(stack) ((unsigned long)(stack)) +#define STACK_BOTTOM_ADDR(stack) \ + ((unsigned long)((stack) + (sizeof(stack)))) + +int set_stack_params(unsigned long stack_top_addr, + unsigned long stack_bottom_addr, + unsigned long stack_size); +int thread_create(struct task_ids *ids, unsigned int flags, + int (*func)(void *), void *arg); #endif /* __LIB_THREAD_H__ */ diff --git a/conts/libl4thread/src/arch b/conts/libl4thread/src/arch new file mode 120000 index 0000000..3e9770f --- /dev/null +++ b/conts/libl4thread/src/arch @@ -0,0 +1 @@ +arch-arm/ \ No newline at end of file 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..908569d --- /dev/null +++ b/conts/libl4thread/src/arch-arm/new_thread.S @@ -0,0 +1,11 @@ +#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 +new_thread_exit: + b new_thread_exit @ We infinitely loop for now. +END_PROC(setup_new_thread) + diff --git a/conts/libl4thread/src/thread.c b/conts/libl4thread/src/thread.c index c362960..e11572c 100644 --- a/conts/libl4thread/src/thread.c +++ b/conts/libl4thread/src/thread.c @@ -1,11 +1,126 @@ /* + * Thread creation userspace helpers * + * Copyright (C) 2009 B Labs Ltd. */ #include +#include +#include +#include +#include -extern void utcb_test(unsigned long utcb_start, unsigned long utcb_end); +/* Symbolic constants and macros */ +#define STACK_PTR(addr) align((addr - 1), 8) +#define IS_STACK_SETUP() (lib_stack_size) -void l4thread_print(void) +/* Extern declarations */ +extern void setup_new_thread(void); + +/* Static variable definitions */ +static unsigned long lib_stack_top_addr; +static unsigned long lib_stack_bot_addr; +static unsigned long lib_stack_size; + +/* Function definitions */ +int set_stack_params(unsigned long stack_top_addr, + unsigned long stack_bottom_addr, + unsigned long stack_size) { - printf("Hello world from libl4thread!\n"); + if (IS_STACK_SETUP()) { + printf("libl4thread: You have already called: %s. Simply, " + "this will have no effect!\n", __FUNCTION__); + return -EPERM; + } + /* + * Stack grows downward so the top of the stack will have + * the lowest numbered address. + */ + if (stack_top_addr >= stack_bottom_addr) { + 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_addr - stack_top_addr) < stack_size) { + printf("libl4thread: the given range size is lesser than " + "the stack size!\n"); + return -EINVAL; + } + lib_stack_bot_addr = stack_bottom_addr; + lib_stack_top_addr = stack_top_addr; + lib_stack_size = stack_size; + + return 0; +} + +int thread_create(struct task_ids *ids, unsigned int flags, + int (*func)(void *), void *arg) +{ + struct exregs_data exregs; + int err; + + /* A few controls before granting access to thread creation */ + if (!IS_STACK_SETUP()) { + printf("libl4thread: Stack has not been set up. Before " + "calling thread_create, set_stack_params " + "has to be called!\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; + } + + if (!(TC_SHARE_SPACE & flags)) { + printf("libl4thread: SAME address space is supported, which " + "means the only way to create a thread is with " + "TC_SHARE_SPACE flag. Other means of creating a " + "thread have not been supported yet!\n"); + return -EINVAL; + } + + /* Get parent's ids */ + l4_getid(ids); + + /* Create thread */ + if ((err = l4_thread_control(THREAD_CREATE | flags, ids)) < 0) { + printf("libl4thread: l4_thread_control(THREAD_CREATE) " + "failed with (%d)!\n", err); + return err; + } + + /* Setup new thread pc, sp, utcb */ + memset(&exregs, 0, sizeof(exregs)); + exregs_set_stack(&exregs, STACK_PTR(lib_stack_bot_addr)); + exregs_set_pc(&exregs, (unsigned long)setup_new_thread); + + if ((err = l4_exchange_registers(&exregs, ids->tid)) < 0) { + printf("libl4thread: l4_exchange_registers failed with " + "(%d)!\n", err); + return err; + } + + /* First word of new stack is arg */ + ((unsigned long *)STACK_PTR(lib_stack_bot_addr))[0] = + (unsigned long)arg; + /* Second word of new stack is function address */ + ((unsigned long *)STACK_PTR(lib_stack_bot_addr))[-1] = + (unsigned long)func; + /* Update the stack address */ + lib_stack_bot_addr -= lib_stack_size; + + /* 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; + } + + return 0; } diff --git a/conts/libl4thread/src/utcb_test.c b/conts/libl4thread/src/utcb_test.c deleted file mode 100644 index b05b7ca..0000000 --- a/conts/libl4thread/src/utcb_test.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This is for testing utcb port from POSIX - */ -#include -#include - -void utcb_test(unsigned long utcb_start, unsigned long utcb_end) -{ - struct utcb_desc *udesc[20]; - unsigned long addr; - int idx = -1; - - printf("%s\n", __FUNCTION__); - - utcb_pool_init(utcb_start, utcb_end); - - // Test-1 - for (int i = 0; i < 10; i++) - udesc[++idx] = utcb_new_desc(); - for (int j = 0; j < 20; ++j) - addr = utcb_new_slot(udesc[idx]); - - // Test 2 - for (int i = 0; i < 3; i++) - udesc[++idx] = utcb_new_desc(); - for (int j = 0; j < 10; ++j) - addr = utcb_new_slot(udesc[idx]); - for (int j = 0; j < 8; j++) { - utcb_delete_slot(udesc[idx], addr); - addr -= 0x100; - } - for (int j = 0; j < 2; ++j) - addr = utcb_new_slot(udesc[idx]); - for (int j = 0; j < 4; j++) { - utcb_delete_slot(udesc[idx], addr); - addr -= 0x100; - } - // Test 3 - for (int i = 0; i < 7; i++) { - utcb_delete_desc(udesc[idx]); - --idx; - } - for (int j = 0; j < 4; ++j) - addr = utcb_new_slot(udesc[idx]); - for (int j = 0; j < 2; j++) { - utcb_delete_slot(udesc[idx], addr); - addr -= 0x100; - } - for (int i = 0; i < 3; i++) - udesc[++idx] = utcb_new_desc(); - for (int i = 0; i < 7; i++) { - utcb_delete_desc(udesc[idx]); - --idx; - } -} From 1256f1a13aa52d1affe5b2cc917a2ee5b30667ad Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Thu, 5 Nov 2009 15:20:54 +0200 Subject: [PATCH 07/19] The second step in creating a thread library. UTCB support has beed added. It has the same drawback as in the stack support: the area in question has to be already mapped-in. There are also some minor fixes for the stack support and the utcb common helper routines. --- conts/libl4thread/include/l4thread/addr.h | 5 +- conts/libl4thread/include/l4thread/thread.h | 14 +- .../include/l4thread/utcb-common.h | 25 +++ conts/libl4thread/include/l4thread/utcb.h | 22 +-- conts/libl4thread/src/addr.c | 6 +- conts/libl4thread/src/thread.c | 32 +++- conts/libl4thread/src/utcb-common.c | 89 +++++++++++ conts/libl4thread/src/utcb.c | 148 ++++++++++-------- 8 files changed, 249 insertions(+), 92 deletions(-) create mode 100644 conts/libl4thread/include/l4thread/utcb-common.h create mode 100644 conts/libl4thread/src/utcb-common.c diff --git a/conts/libl4thread/include/l4thread/addr.h b/conts/libl4thread/include/l4thread/addr.h index 5bbc69d..e7b4519 100644 --- a/conts/libl4thread/include/l4thread/addr.h +++ b/conts/libl4thread/include/l4thread/addr.h @@ -18,8 +18,9 @@ struct address_pool { int address_pool_init_with_idpool(struct address_pool *pool, struct id_pool *idpool, unsigned long start, unsigned long end); -int address_pool_init(struct address_pool *pool, unsigned long start, - unsigned long end); +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); diff --git a/conts/libl4thread/include/l4thread/thread.h b/conts/libl4thread/include/l4thread/thread.h index 658d17b..ce41f16 100644 --- a/conts/libl4thread/include/l4thread/thread.h +++ b/conts/libl4thread/include/l4thread/thread.h @@ -6,13 +6,21 @@ #ifndef __LIB_THREAD_H__ #define __LIB_THREAD_H__ -#define STACK_TOP_ADDR(stack) ((unsigned long)(stack)) -#define STACK_BOTTOM_ADDR(stack) \ - ((unsigned long)((stack) + (sizeof(stack)))) +#define START_ADDR(addr) ((unsigned long)(addr)) +#define END_ADDR(addr) ((unsigned long)((addr) + (sizeof(addr)))) + +#define STACK_TOP_ADDR(stack) (START_ADDR(stack)) +#define STACK_BOTTOM_ADDR(stack) (END_ADDR(stack)) + +#define UTCB_START_ADDR(utcb) (START_ADDR(utcb)) +#define UTCB_END_ADDR(utcb) (END_ADDR(utcb)) int set_stack_params(unsigned long stack_top_addr, unsigned long stack_bottom_addr, unsigned long stack_size); +int set_utcb_params(unsigned long utcb_start_addr, + unsigned long utcb_end_addr); + int thread_create(struct task_ids *ids, unsigned int flags, int (*func)(void *), void *arg); diff --git a/conts/libl4thread/include/l4thread/utcb-common.h b/conts/libl4thread/include/l4thread/utcb-common.h new file mode 100644 index 0000000..e5f5fef --- /dev/null +++ b/conts/libl4thread/include/l4thread/utcb-common.h @@ -0,0 +1,25 @@ +/* + * UTCB handling common helper routines + * + * Copyright (C) 2009 B Labs Ltd. + */ +#ifndef __UTCB_COMMON_H__ +#define __UTCB_COMMON_H__ + +#include + +struct utcb_desc { + struct link list; + unsigned long utcb_base; + struct id_pool *slots; +}; + +int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end); + +unsigned long utcb_new_slot(struct utcb_desc *desc); +int utcb_delete_slot(struct utcb_desc *desc, unsigned long address); + +struct utcb_desc *utcb_new_desc(void); +int utcb_delete_desc(struct utcb_desc *desc); + +#endif /* __UTCB_COMMON_H__ */ diff --git a/conts/libl4thread/include/l4thread/utcb.h b/conts/libl4thread/include/l4thread/utcb.h index 464bd45..32049e5 100644 --- a/conts/libl4thread/include/l4thread/utcb.h +++ b/conts/libl4thread/include/l4thread/utcb.h @@ -3,23 +3,13 @@ * * Copyright (C) 2009 B Labs Ltd. */ -#ifndef __UTCB_H__ -#define __UTCB_H__ +#ifndef __LIB_UTCB_H__ +#define __LIB_UTCB_H__ -#include +#define IS_UTCB_SETUP() (udesc_ptr) -struct utcb_desc { - struct link list; - unsigned long utcb_base; - struct id_pool *slots; -}; +struct utcb_desc *udesc_ptr; -int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end); +unsigned long get_utcb_addr(void); -unsigned long utcb_new_slot(struct utcb_desc *desc); -int utcb_delete_slot(struct utcb_desc *desc, unsigned long address); - -struct utcb_desc *utcb_new_desc(void); -int utcb_delete_desc(struct utcb_desc *desc); - -#endif /* __UTCB_H__ */ +#endif /* __LIB_UTCB_H__ */ diff --git a/conts/libl4thread/src/addr.c b/conts/libl4thread/src/addr.c index 10206bd..90c67dd 100644 --- a/conts/libl4thread/src/addr.c +++ b/conts/libl4thread/src/addr.c @@ -22,9 +22,11 @@ int address_pool_init_with_idpool(struct address_pool *pool, return 0; } -int address_pool_init(struct address_pool *pool, unsigned long start, unsigned long end) +int address_pool_init(struct address_pool *pool, + unsigned long start, unsigned long end, + int size) { - if ((pool->idpool = id_pool_new_init(__pfn(end - start))) < 0) + if ((pool->idpool = id_pool_new_init((end - start) / size)) < 0) return (int)pool->idpool; pool->start = start; pool->end = end; diff --git a/conts/libl4thread/src/thread.c b/conts/libl4thread/src/thread.c index e11572c..cfaaaca 100644 --- a/conts/libl4thread/src/thread.c +++ b/conts/libl4thread/src/thread.c @@ -8,6 +8,7 @@ #include #include #include +#include /* Symbolic constants and macros */ #define STACK_PTR(addr) align((addr - 1), 8) @@ -26,11 +27,18 @@ int set_stack_params(unsigned long stack_top_addr, unsigned long stack_bottom_addr, unsigned long stack_size) { + /* Ensure that arguments are valid. */ if (IS_STACK_SETUP()) { printf("libl4thread: You have already called: %s. Simply, " "this will have no effect!\n", __FUNCTION__); return -EPERM; } + if (!stack_top_addr || !stack_bottom_addr) { + printf("libl4thread: stack address range cannot contain " + "0x00000000 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. @@ -44,12 +52,15 @@ int set_stack_params(unsigned long stack_top_addr, printf("libl4thread: Stack size cannot be zero!\n"); return -EINVAL; } - /* stack_size at least must be equal to the difference */ + /* stack_size at least must be equal to the difference. */ if ((stack_bottom_addr - stack_top_addr) < stack_size) { printf("libl4thread: the given range size is lesser than " - "the stack size!\n"); + "the stack size(0x%x)!\n", stack_size); return -EINVAL; } + /* Arguments passed the validity tests. */ + + /* Initialize internal variables */ lib_stack_bot_addr = stack_bottom_addr; lib_stack_top_addr = stack_top_addr; lib_stack_size = stack_size; @@ -61,13 +72,15 @@ int thread_create(struct task_ids *ids, unsigned int flags, int (*func)(void *), void *arg) { struct exregs_data exregs; + unsigned long utcb_addr; int err; /* A few controls before granting access to thread creation */ - if (!IS_STACK_SETUP()) { - printf("libl4thread: Stack has not been set up. Before " - "calling thread_create, set_stack_params " - "has to be called!\n"); + if (!IS_STACK_SETUP() || !IS_UTCB_SETUP()) { + printf("libl4thread: Stack and/or utcb have not been set up. " + "Before calling thread_create, set_stack_params " + "and/or set_utcb_params have to be called with valid " + "arguments!\n"); return -EPERM; } @@ -85,6 +98,12 @@ int thread_create(struct task_ids *ids, unsigned int flags, return -EINVAL; } + /* Get a utcb addr for this thread */ + if (!(utcb_addr = get_utcb_addr())) { + printf("libl4thread: No utcb address left!\n"); + return -ENOMEM; + } + /* Get parent's ids */ l4_getid(ids); @@ -99,6 +118,7 @@ int thread_create(struct task_ids *ids, unsigned int flags, memset(&exregs, 0, sizeof(exregs)); exregs_set_stack(&exregs, STACK_PTR(lib_stack_bot_addr)); 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 " diff --git a/conts/libl4thread/src/utcb-common.c b/conts/libl4thread/src/utcb-common.c new file mode 100644 index 0000000..38df843 --- /dev/null +++ b/conts/libl4thread/src/utcb-common.c @@ -0,0 +1,89 @@ +/* + * UTCB management in Codezero + * + * Copyright © 2009 B Labs Ltd + */ +#include +#include +#include +#include + +/* Globally disjoint utcb virtual region pool */ +static struct address_pool utcb_region_pool; + +int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end) +{ + int err; + + /* Initialise the global utcb virtual address pool */ + if ((err = address_pool_init(&utcb_region_pool, + utcb_start, utcb_end, + UTCB_SIZE) < 0)) { + printf("UTCB address pool initialisation failed.\n"); + return err; + } + + return 0; +} + +static inline void *utcb_new_address(int npages) +{ + return address_new(&utcb_region_pool, npages); +} + +static inline int utcb_delete_address(void *utcb_address, int npages) +{ + return address_del(&utcb_region_pool, utcb_address, npages); +} + +/* Return an empty utcb slot in this descriptor */ +unsigned long utcb_new_slot(struct utcb_desc *desc) +{ + int slot; + + if ((slot = id_new(desc->slots)) < 0) + return 0; + else + return desc->utcb_base + (unsigned long)slot * UTCB_SIZE; +} + +int utcb_delete_slot(struct utcb_desc *desc, unsigned long address) +{ + BUG_ON(id_del(desc->slots, (address - desc->utcb_base) + / UTCB_SIZE) < 0); + return 0; +} + +struct utcb_desc *utcb_new_desc(void) +{ + struct utcb_desc *d; + + /* Allocate a new descriptor */ + if (!(d = kzalloc(sizeof(*d)))) + return 0; + + link_init(&d->list); + + /* We currently assume UTCB is smaller than PAGE_SIZE */ + BUG_ON(UTCB_SIZE > PAGE_SIZE); + + /* Initialise utcb slots */ + d->slots = id_pool_new_init(PAGE_SIZE / UTCB_SIZE); + + /* Obtain a new and unique utcb base */ + /* FIXME: Use variable size than a page */ + d->utcb_base = (unsigned long)utcb_new_address(1); + + return d; +} + +int utcb_delete_desc(struct utcb_desc *desc) +{ + /* Return descriptor address */ + utcb_delete_address((void *)desc->utcb_base, 1); + + /* Free the descriptor */ + kfree(desc); + + return 0; +} diff --git a/conts/libl4thread/src/utcb.c b/conts/libl4thread/src/utcb.c index 9dcc187..7298bf0 100644 --- a/conts/libl4thread/src/utcb.c +++ b/conts/libl4thread/src/utcb.c @@ -1,88 +1,110 @@ /* - * UTCB management in Codezero + * UTCB handling helper routines * - * Copyright © 2009 B Labs Ltd + * Copyright (C) 2009 B Labs Ltd. */ #include -#include -#include +#include +#include +#include #include +#include +#include -/* Globally disjoint utcb virtual region pool */ -static struct address_pool utcb_region_pool; +/* Static variable definitions */ +static unsigned long utcb_end_max_addr; -int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end) +/* Function definitions */ +unsigned long get_utcb_addr(void) { + unsigned long utcb_addr; + + if (!(utcb_addr = utcb_new_slot(udesc_ptr))) { + udesc_ptr = utcb_new_desc(); + utcb_addr = utcb_new_slot(udesc_ptr); + } + + if (utcb_addr >= utcb_end_max_addr) + return 0; + + return utcb_addr; +} + +static int set_utcb_addr(void) +{ + struct exregs_data exregs; + unsigned long utcb_addr; + struct task_ids ids; int err; - /* Initialise the global utcb virtual address pool */ - if ((err = address_pool_init(&utcb_region_pool, - utcb_start, utcb_end) < 0)) { - printf("UTCB address pool initialisation failed.\n"); + l4_getid(&ids); + // FIXME: its tid must be 0. + udesc_ptr = utcb_new_desc(); + utcb_addr = get_utcb_addr(); + + memset(&exregs, 0, sizeof(exregs)); + 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); return err; } return 0; } -static inline void *utcb_new_address(int npages) +int set_utcb_params(unsigned long utcb_start_addr, + unsigned long utcb_end_addr) { - return address_new(&utcb_region_pool, npages); -} + int err; -static inline int utcb_delete_address(void *utcb_address, int npages) -{ - return address_del(&utcb_region_pool, utcb_address, npages); -} + /* Ensure that arguments are valid. */ + if (IS_UTCB_SETUP()) { + printf("libl4thread: You have already called: %s. Simply, " + "this will have no effect!\n", __FUNCTION__); + return -EPERM; + } + if (!utcb_start_addr || !utcb_end_addr) { + printf("libl4thread: utcb address range cannot contain " + "0x00000000 as a start and/or end address(es)!\n"); + return -EINVAL; + } + /* Check if the start address is aligned on UTCB_SIZE. */ + if (utcb_start_addr & !UTCB_SIZE) { + printf("libl4thread: utcb start address must be aligned " + "on UTCB_SIZE(0x%x)\n", UTCB_SIZE); + return -EINVAL; + } + /* The range must be a valid one. */ + if (utcb_start_addr >= utcb_end_addr) { + printf("libl4thread: utcb end address must be bigger " + "than utcb start address!\n"); + return -EINVAL; + } + /* + * This check guarantees two things: + * 1. The range must be multiple of UTCB_SIZE, at least one item. + * 2. utcb_end_addr is aligned on UTCB_SIZE + */ + if ((utcb_end_addr - utcb_start_addr) % UTCB_SIZE) { + printf("libl4thread: the given range size must be multiple " + "of the utcb size(%d)!\n", UTCB_SIZE); + return -EINVAL; + } + /* Arguments passed the validity tests. */ -/* Return an empty utcb slot in this descriptor */ -unsigned long utcb_new_slot(struct utcb_desc *desc) -{ - int slot; + /* Init utcb virtual address pool */ + utcb_pool_init(utcb_start_addr, utcb_end_addr); - if ((slot = id_new(desc->slots)) < 0) - return 0; - else - return desc->utcb_base + (unsigned long)slot * UTCB_SIZE; -} + utcb_end_max_addr = utcb_end_addr; + + /* The very first thread's utcb address is assigned. */ + if ((err = set_utcb_addr()) < 0) + return err; -int utcb_delete_slot(struct utcb_desc *desc, unsigned long address) -{ - BUG_ON(id_del(desc->slots, (address - desc->utcb_base) - / UTCB_SIZE) < 0); return 0; } -struct utcb_desc *utcb_new_desc(void) -{ - struct utcb_desc *d; +/*void destroy_utcb(void) {}*/ - /* Allocate a new descriptor */ - if (!(d = kzalloc(sizeof(*d)))) - return 0; - - link_init(&d->list); - - /* We currently assume UTCB is smaller than PAGE_SIZE */ - BUG_ON(UTCB_SIZE > PAGE_SIZE); - - /* Initialise utcb slots */ - d->slots = id_pool_new_init(PAGE_SIZE / UTCB_SIZE); - - /* Obtain a new and unique utcb base */ - /* FIXME: Use variable size than a page */ - d->utcb_base = (unsigned long)utcb_new_address(1); - - return d; -} - -int utcb_delete_desc(struct utcb_desc *desc) -{ - /* Return descriptor address */ - utcb_delete_address((void *)desc->utcb_base, 1); - - /* Free the descriptor */ - kfree(desc); - - return 0; -} From 20f2b2bfdb4bf5f93bd8497dc0389ccdbc1ae73e Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Thu, 5 Nov 2009 22:09:37 +0200 Subject: [PATCH 08/19] Lots of cosmetic changes to the thread library. --- conts/libl4thread/include/l4thread/thread.h | 18 ++---- conts/libl4thread/src/thread.c | 62 ++++++++++----------- conts/libl4thread/src/utcb.c | 43 +++++++------- 3 files changed, 54 insertions(+), 69 deletions(-) diff --git a/conts/libl4thread/include/l4thread/thread.h b/conts/libl4thread/include/l4thread/thread.h index ce41f16..c1ce0a9 100644 --- a/conts/libl4thread/include/l4thread/thread.h +++ b/conts/libl4thread/include/l4thread/thread.h @@ -6,22 +6,12 @@ #ifndef __LIB_THREAD_H__ #define __LIB_THREAD_H__ -#define START_ADDR(addr) ((unsigned long)(addr)) -#define END_ADDR(addr) ((unsigned long)((addr) + (sizeof(addr)))) - -#define STACK_TOP_ADDR(stack) (START_ADDR(stack)) -#define STACK_BOTTOM_ADDR(stack) (END_ADDR(stack)) - -#define UTCB_START_ADDR(utcb) (START_ADDR(utcb)) -#define UTCB_END_ADDR(utcb) (END_ADDR(utcb)) - -int set_stack_params(unsigned long stack_top_addr, - unsigned long stack_bottom_addr, +int set_stack_params(unsigned long stack_top, + unsigned long stack_bottom, unsigned long stack_size); -int set_utcb_params(unsigned long utcb_start_addr, - unsigned long utcb_end_addr); +int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end); -int thread_create(struct task_ids *ids, unsigned int flags, +int l4thread_create(struct task_ids *ids, unsigned int flags, int (*func)(void *), void *arg); #endif /* __LIB_THREAD_H__ */ diff --git a/conts/libl4thread/src/thread.c b/conts/libl4thread/src/thread.c index cfaaaca..19b856e 100644 --- a/conts/libl4thread/src/thread.c +++ b/conts/libl4thread/src/thread.c @@ -11,7 +11,6 @@ #include /* Symbolic constants and macros */ -#define STACK_PTR(addr) align((addr - 1), 8) #define IS_STACK_SETUP() (lib_stack_size) /* Extern declarations */ @@ -23,19 +22,19 @@ static unsigned long lib_stack_bot_addr; static unsigned long lib_stack_size; /* Function definitions */ -int set_stack_params(unsigned long stack_top_addr, - unsigned long stack_bottom_addr, +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. Simply, " - "this will have no effect!\n", __FUNCTION__); + printf("libl4thread: You have already called: %s.\n", + __FUNCTION__); return -EPERM; } - if (!stack_top_addr || !stack_bottom_addr) { - printf("libl4thread: stack address range cannot contain " - "0x00000000 as a start and/or end address(es)!\n"); + 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. @@ -43,32 +42,32 @@ int set_stack_params(unsigned long stack_top_addr, * Stack grows downward so the top of the stack will have * the lowest numbered address. */ - if (stack_top_addr >= stack_bottom_addr) { + if (stack_top >= stack_bottom) { printf("libl4thread: Stack bottom address must be bigger " - "than stack top address!\n"); + "than stack top address.\n"); return -EINVAL; } if (!stack_size) { - printf("libl4thread: Stack size cannot be zero!\n"); + printf("libl4thread: Stack size cannot be zero.\n"); return -EINVAL; } /* stack_size at least must be equal to the difference. */ - if ((stack_bottom_addr - stack_top_addr) < stack_size) { - printf("libl4thread: the given range size is lesser than " - "the stack size(0x%x)!\n", stack_size); + 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_addr; - lib_stack_top_addr = stack_top_addr; + lib_stack_bot_addr = stack_bottom; + lib_stack_top_addr = stack_top; lib_stack_size = stack_size; return 0; } -int thread_create(struct task_ids *ids, unsigned int flags, +int l4thread_create(struct task_ids *ids, unsigned int flags, int (*func)(void *), void *arg) { struct exregs_data exregs; @@ -77,30 +76,27 @@ int thread_create(struct task_ids *ids, unsigned int flags, /* A few controls before granting access to thread creation */ if (!IS_STACK_SETUP() || !IS_UTCB_SETUP()) { - printf("libl4thread: Stack and/or utcb have not been set up. " - "Before calling thread_create, set_stack_params " - "and/or set_utcb_params have to be called with valid " - "arguments!\n"); + printf("libl4thread: Stack and/or utcb have not been " + "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"); + printf("libl4thread: No stack space left.\n"); return -ENOMEM; } if (!(TC_SHARE_SPACE & flags)) { - printf("libl4thread: SAME address space is supported, which " - "means the only way to create a thread is with " - "TC_SHARE_SPACE flag. Other means of creating a " - "thread have not been supported yet!\n"); + printf("libl4thread: Only allows shared space thread " + "creation.\n"); + return -EINVAL; } /* Get a utcb addr for this thread */ if (!(utcb_addr = get_utcb_addr())) { - printf("libl4thread: No utcb address left!\n"); + printf("libl4thread: No utcb address left.\n"); return -ENOMEM; } @@ -110,27 +106,27 @@ int thread_create(struct task_ids *ids, unsigned int flags, /* Create thread */ if ((err = l4_thread_control(THREAD_CREATE | flags, ids)) < 0) { printf("libl4thread: l4_thread_control(THREAD_CREATE) " - "failed with (%d)!\n", err); + "failed with (%d).\n", err); return err; } /* Setup new thread pc, sp, utcb */ memset(&exregs, 0, sizeof(exregs)); - exregs_set_stack(&exregs, STACK_PTR(lib_stack_bot_addr)); + exregs_set_stack(&exregs, align((lib_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); + "(%d).\n", err); return err; } /* First word of new stack is arg */ - ((unsigned long *)STACK_PTR(lib_stack_bot_addr))[0] = + ((unsigned long *)align((lib_stack_bot_addr - 1), 8))[0] = (unsigned long)arg; /* Second word of new stack is function address */ - ((unsigned long *)STACK_PTR(lib_stack_bot_addr))[-1] = + ((unsigned long *)align((lib_stack_bot_addr - 1), 8))[-1] = (unsigned long)func; /* Update the stack address */ lib_stack_bot_addr -= lib_stack_size; @@ -138,7 +134,7 @@ int thread_create(struct task_ids *ids, unsigned int flags, /* 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); + "failed with (%d).\n", err); return err; } diff --git a/conts/libl4thread/src/utcb.c b/conts/libl4thread/src/utcb.c index 7298bf0..049bcbe 100644 --- a/conts/libl4thread/src/utcb.c +++ b/conts/libl4thread/src/utcb.c @@ -12,7 +12,7 @@ #include /* Static variable definitions */ -static unsigned long utcb_end_max_addr; +static unsigned long lib_utcb_end_addr; /* Function definitions */ unsigned long get_utcb_addr(void) @@ -24,7 +24,7 @@ unsigned long get_utcb_addr(void) utcb_addr = utcb_new_slot(udesc_ptr); } - if (utcb_addr >= utcb_end_max_addr) + if (utcb_addr >= lib_utcb_end_addr) return 0; return utcb_addr; @@ -47,57 +47,56 @@ static int set_utcb_addr(void) 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_addr, - unsigned long utcb_end_addr) +int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) { int err; /* Ensure that arguments are valid. */ if (IS_UTCB_SETUP()) { - printf("libl4thread: You have already called: %s. Simply, " - "this will have no effect!\n", __FUNCTION__); + printf("libl4thread: You have already called: %s.\n", + __FUNCTION__); return -EPERM; } - if (!utcb_start_addr || !utcb_end_addr) { - printf("libl4thread: utcb address range cannot contain " - "0x00000000 as a start and/or end address(es)!\n"); + 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_addr & !UTCB_SIZE) { - printf("libl4thread: utcb start address must be aligned " - "on UTCB_SIZE(0x%x)\n", UTCB_SIZE); + if (utcb_start & !UTCB_SIZE) { + printf("libl4thread: Utcb start address must be aligned " + "on UTCB_SIZE(0x%x).\n", UTCB_SIZE); return -EINVAL; } /* The range must be a valid one. */ - if (utcb_start_addr >= utcb_end_addr) { - printf("libl4thread: utcb end address must be bigger " - "than utcb start address!\n"); + if (utcb_start >= utcb_end) { + printf("libl4thread: Utcb end address must be bigger " + "than utcb start address.\n"); return -EINVAL; } /* * This check guarantees two things: * 1. The range must be multiple of UTCB_SIZE, at least one item. - * 2. utcb_end_addr is aligned on UTCB_SIZE + * 2. utcb_end is aligned on UTCB_SIZE */ - if ((utcb_end_addr - utcb_start_addr) % UTCB_SIZE) { - printf("libl4thread: the given range size must be multiple " - "of the utcb size(%d)!\n", UTCB_SIZE); + if ((utcb_end - utcb_start) % UTCB_SIZE) { + printf("libl4thread: The given range size must be multiple " + "of the utcb size(%d).\n", UTCB_SIZE); return -EINVAL; } /* Arguments passed the validity tests. */ /* Init utcb virtual address pool */ - utcb_pool_init(utcb_start_addr, utcb_end_addr); + utcb_pool_init(utcb_start, utcb_end); - utcb_end_max_addr = utcb_end_addr; + lib_utcb_end_addr = utcb_end; /* The very first thread's utcb address is assigned. */ if ((err = set_utcb_addr()) < 0) From 344362e9daa61d188e284138025cf7982d4fbc2f Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Tue, 10 Nov 2009 14:46:54 +0200 Subject: [PATCH 09/19] Task list is introduced to the thread library. In order to do resource recycling we need a table structure. In the search of one, we concluded that a task list will make things easier when we start adding COPY and NEW space handling. This commit is for utcb recycling. Now, it does not support thread trees more than one level depth. Thus, to be able to test it, we preferred l4thread_destroy instead of l4thread_exit. --- conts/libl4thread/include/l4thread/tcb.h | 35 ++++++++ conts/libl4thread/include/l4thread/thread.h | 1 + conts/libl4thread/include/l4thread/utcb.h | 7 +- conts/libl4thread/src/tcb.c | 56 ++++++++++++ conts/libl4thread/src/thread.c | 55 ++++++++++-- conts/libl4thread/src/utcb.c | 95 +++++++++++++++------ 6 files changed, 211 insertions(+), 38 deletions(-) create mode 100644 conts/libl4thread/include/l4thread/tcb.h create mode 100644 conts/libl4thread/src/tcb.c diff --git a/conts/libl4thread/include/l4thread/tcb.h b/conts/libl4thread/include/l4thread/tcb.h new file mode 100644 index 0000000..1c81111 --- /dev/null +++ b/conts/libl4thread/include/l4thread/tcb.h @@ -0,0 +1,35 @@ +/* + * Thread control block. + * + * Copyright (C) 2009 B Labs Ltd. + */ +#ifndef __LIB_TCB_H__ +#define __LIB_TCB_H__ + +#include + +/* Keeps all the struct utcb_descs belonging to a thread group together. */ +struct utcb_head { + struct link list; +}; + +/* A simple thread control block for the thread library. */ +struct l4t_tcb { + struct link list; + int tid; + struct utcb_head *utcb_head; + unsigned long utcb_addr; +}; + +/* This struct keeps track of all the threads handled by the thread lib. */ +struct l4t_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); + +#endif /* __LIB_TCB_H__ */ diff --git a/conts/libl4thread/include/l4thread/thread.h b/conts/libl4thread/include/l4thread/thread.h index c1ce0a9..319233e 100644 --- a/conts/libl4thread/include/l4thread/thread.h +++ b/conts/libl4thread/include/l4thread/thread.h @@ -13,5 +13,6 @@ int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end); int l4thread_create(struct task_ids *ids, unsigned int flags, int (*func)(void *), void *arg); +void l4thread_kill(struct task_ids *ids); #endif /* __LIB_THREAD_H__ */ diff --git a/conts/libl4thread/include/l4thread/utcb.h b/conts/libl4thread/include/l4thread/utcb.h index 32049e5..f16f310 100644 --- a/conts/libl4thread/include/l4thread/utcb.h +++ b/conts/libl4thread/include/l4thread/utcb.h @@ -6,10 +6,9 @@ #ifndef __LIB_UTCB_H__ #define __LIB_UTCB_H__ -#define IS_UTCB_SETUP() (udesc_ptr) +#include -struct utcb_desc *udesc_ptr; - -unsigned long get_utcb_addr(void); +unsigned long get_utcb_addr(struct l4t_tcb *task); +int delete_utcb_addr(struct l4t_tcb *task); #endif /* __LIB_UTCB_H__ */ diff --git a/conts/libl4thread/src/tcb.c b/conts/libl4thread/src/tcb.c new file mode 100644 index 0000000..d0125bb --- /dev/null +++ b/conts/libl4thread/src/tcb.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include + +/* Global task list. */ +struct l4t_global_list l4t_global_tasks = { + .list = { &l4t_global_tasks.list, &l4t_global_tasks.list }, + .total = 0, +}; + +/* Function definitions */ +void l4t_global_add_task(struct l4t_tcb *task) +{ + BUG_ON(!list_empty(&task->list)); + list_insert_tail(&task->list, &l4t_global_tasks.list); + l4t_global_tasks.total++; +} + +void l4t_global_remove_task(struct l4t_tcb *task) +{ + BUG_ON(list_empty(&task->list)); + list_remove_init(&task->list); + BUG_ON(--l4t_global_tasks.total < 0); +} + +struct l4t_tcb *l4t_find_task(int tid) +{ + struct l4t_tcb *t; + + list_foreach_struct(t, &l4t_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 l4t_tcb *task; + + if (!(task = kzalloc(sizeof(struct l4t_tcb)))) + return PTR_ERR(-ENOMEM); + + link_init(&task->list); + + if ((parent) && (flags & TC_SHARE_SPACE)) + task->utcb_head = parent->utcb_head; + else { + if (!(task->utcb_head = kzalloc(sizeof(struct utcb_head)))) + return PTR_ERR(-ENOMEM); + link_init(&task->utcb_head->list); + } + + return task; +} diff --git a/conts/libl4thread/src/thread.c b/conts/libl4thread/src/thread.c index 19b856e..87e84b4 100644 --- a/conts/libl4thread/src/thread.c +++ b/conts/libl4thread/src/thread.c @@ -8,6 +8,7 @@ #include #include #include +#include #include /* Symbolic constants and macros */ @@ -72,10 +73,12 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, { struct exregs_data exregs; unsigned long utcb_addr; + struct l4t_tcb *parent, *child; int err; /* A few controls before granting access to thread creation */ - if (!IS_STACK_SETUP() || !IS_UTCB_SETUP()) { + // FIXME: check if utcb region is setup + if (!IS_STACK_SETUP()) { printf("libl4thread: Stack and/or utcb have not been " "set up.\n"); return -EPERM; @@ -87,6 +90,8 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, return -ENOMEM; } + // FIXME: Check if there is enough utcb space + if (!(TC_SHARE_SPACE & flags)) { printf("libl4thread: Only allows shared space thread " "creation.\n"); @@ -94,19 +99,32 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, return -EINVAL; } - /* Get a utcb addr for this thread */ - if (!(utcb_addr = get_utcb_addr())) { - printf("libl4thread: No utcb address left.\n"); + /* Get parent's ids and find the tcb belonging to it. */ + l4_getid(ids); + if (!(parent = l4t_find_task(ids->tid))) + return-ESRCH; + + /* Allocate tcb for the child. */ + if (!(child = l4t_tcb_alloc_init(parent, flags))) { + printf("libl4thread: No heap space left.\n"); return -ENOMEM; } - /* Get parent's ids */ - l4_getid(ids); + /* Get a utcb addr for this thread */ + 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; + } /* 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; } @@ -119,6 +137,7 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, 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; } @@ -131,6 +150,10 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, /* Update the stack address */ lib_stack_bot_addr -= lib_stack_size; + /* Add child to the global task list */ + child->tid = ids->tid; + l4t_global_add_task(child); + /* Start the new thread */ if ((err = l4_thread_control(THREAD_RUN, ids)) < 0) { printf("libl4thread: l4_thread_control(THREAD_RUN) " @@ -140,3 +163,23 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, return 0; } + +void l4thread_kill(struct task_ids *ids) +{ + struct l4t_tcb *task; + + /* Find the task to be killed. */ + task = l4t_find_task(ids->tid); + + /* Delete the utcb address. */ + delete_utcb_addr(task); + + /* Remove child from the global task list. */ + l4t_global_remove_task(task); + + // FIXME: We assume that main thread never leaves the scene + kfree(task); + + /* Finally, destroy the thread. */ + l4_thread_control(THREAD_DESTROY, ids); +} diff --git a/conts/libl4thread/src/utcb.c b/conts/libl4thread/src/utcb.c index 049bcbe..4dd7fef 100644 --- a/conts/libl4thread/src/utcb.c +++ b/conts/libl4thread/src/utcb.c @@ -8,43 +8,86 @@ #include #include #include +#include #include #include -/* Static variable definitions */ -static unsigned long lib_utcb_end_addr; +/* Extern declarations */ +extern struct l4t_global_list l4t_global_tasks; /* Function definitions */ -unsigned long get_utcb_addr(void) +unsigned long get_utcb_addr(struct l4t_tcb *task) { - unsigned long utcb_addr; + struct utcb_desc *udesc; + unsigned long slot; - if (!(utcb_addr = utcb_new_slot(udesc_ptr))) { - udesc_ptr = utcb_new_desc(); - utcb_addr = utcb_new_slot(udesc_ptr); + /* Setting this up twice is a bug. */ + BUG_ON(task->utcb_addr); + + /* Search for an empty utcb slot already allocated to this space. */ + list_foreach_struct(udesc, &task->utcb_head->list, list) + if ((slot = utcb_new_slot(udesc))) + goto found; + + /* Allocate a new utcb memory region and return its base. */ + udesc = utcb_new_desc(); + slot = utcb_new_slot(udesc); + list_insert(&udesc->list, &task->utcb_head->list); +found: + task->utcb_addr = slot; + + return slot; +} + +int delete_utcb_addr(struct l4t_tcb *task) +{ + struct utcb_desc *udesc; + + list_foreach_struct(udesc, &task->utcb_head->list, list) { + /* FIXME: Use variable alignment than a page */ + /* Detect matching slot */ + if (page_align(task->utcb_addr) == udesc->utcb_base) { + + /* Delete slot from the descriptor */ + utcb_delete_slot(udesc, task->utcb_addr); + + /* Is the desc completely empty now? */ + if (id_is_empty(udesc->slots)) { + /* Unlink desc from its list */ + list_remove_init(&udesc->list); + /* Delete the descriptor */ + utcb_delete_desc(udesc); + } + return 0; /* Finished */ + } } - - if (utcb_addr >= lib_utcb_end_addr) - return 0; - - return utcb_addr; + BUG(); } static int set_utcb_addr(void) { struct exregs_data exregs; - unsigned long utcb_addr; struct task_ids ids; + struct l4t_tcb *task; + struct utcb_desc *udesc; int err; - l4_getid(&ids); - // FIXME: its tid must be 0. - udesc_ptr = utcb_new_desc(); - utcb_addr = get_utcb_addr(); + /* Create a task. */ + if (IS_ERR(task = l4t_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++; + + udesc = utcb_new_desc(); + 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)utcb_addr); + exregs_set_utcb(&exregs, (unsigned long)task->utcb_addr); + l4_getid(&ids); if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) { printf("libl4thread: l4_exchange_registers failed with " "(%d).\n", err); @@ -59,11 +102,12 @@ int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) int err; /* Ensure that arguments are valid. */ - if (IS_UTCB_SETUP()) { - printf("libl4thread: You have already called: %s.\n", - __FUNCTION__); - return -EPERM; - } + // FIXME: Check if set_utcb_params is called + /*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"); @@ -96,14 +140,9 @@ int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) /* Init utcb virtual address pool */ utcb_pool_init(utcb_start, utcb_end); - lib_utcb_end_addr = utcb_end; - /* The very first thread's utcb address is assigned. */ if ((err = set_utcb_addr()) < 0) return err; return 0; } - -/*void destroy_utcb(void) {}*/ - From c8a55f88344c79bc47a2c9829033721a927906b3 Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Tue, 10 Nov 2009 21:48:48 +0200 Subject: [PATCH 10/19] Stack recycling is added to the thread library. Still, it does not support thread trees which have more than one level depth. --- conts/libl4thread/include/l4thread/addr.h | 4 +- conts/libl4thread/include/l4thread/stack.h | 16 ++++++++ conts/libl4thread/include/l4thread/tcb.h | 1 + .../include/l4thread/utcb-common.h | 2 +- conts/libl4thread/src/addr.c | 14 +++---- conts/libl4thread/src/stack.c | 37 ++++++++++++++++++ conts/libl4thread/src/thread.c | 39 ++++++++++--------- conts/libl4thread/src/utcb-common.c | 12 +++--- conts/libl4thread/src/utcb.c | 4 +- 9 files changed, 93 insertions(+), 36 deletions(-) create mode 100644 conts/libl4thread/include/l4thread/stack.h create mode 100644 conts/libl4thread/src/stack.c diff --git a/conts/libl4thread/include/l4thread/addr.h b/conts/libl4thread/include/l4thread/addr.h index e7b4519..900d790 100644 --- a/conts/libl4thread/include/l4thread/addr.h +++ b/conts/libl4thread/include/l4thread/addr.h @@ -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..d49a79a --- /dev/null +++ b/conts/libl4thread/include/l4thread/stack.h @@ -0,0 +1,16 @@ +/* + * Stack region helper routines. + * + * Copyright (C) 2009 B Labs Ltd. + */ +#ifndef __LIB_STACK_H__ +#define __LIB_STACK_H__ + +int stack_pool_init(unsigned long stack_start, + unsigned long stack_end, + unsigned long stack_size); + +void *stack_new_space(int nitems, int size); +int stack_delete_space(void *stack_address, int nitems, int size); + +#endif /* __LIB_STACK_H__ */ diff --git a/conts/libl4thread/include/l4thread/tcb.h b/conts/libl4thread/include/l4thread/tcb.h index 1c81111..a2f399e 100644 --- a/conts/libl4thread/include/l4thread/tcb.h +++ b/conts/libl4thread/include/l4thread/tcb.h @@ -19,6 +19,7 @@ struct l4t_tcb { int tid; struct utcb_head *utcb_head; unsigned long utcb_addr; + unsigned long stack_addr; }; /* This struct keeps track of all the threads handled by the thread lib. */ 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/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/stack.c b/conts/libl4thread/src/stack.c new file mode 100644 index 0000000..a48de63 --- /dev/null +++ b/conts/libl4thread/src/stack.c @@ -0,0 +1,37 @@ +/* + * Stack management in libl4thread. + * + * Copyright © 2009 B Labs Ltd. + */ +#include +#include + +/* 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 *stack_new_space(int nitems, int size) +{ + return address_new(&stack_region_pool, nitems, size); +} + +int stack_delete_space(void *stack_address, int nitems, int size) +{ + return address_del(&stack_region_pool, stack_address, nitems, size); +} diff --git a/conts/libl4thread/src/thread.c b/conts/libl4thread/src/thread.c index 87e84b4..c7f643b 100644 --- a/conts/libl4thread/src/thread.c +++ b/conts/libl4thread/src/thread.c @@ -10,6 +10,7 @@ #include #include #include +#include /* Symbolic constants and macros */ #define IS_STACK_SETUP() (lib_stack_size) @@ -18,8 +19,6 @@ extern void setup_new_thread(void); /* Static variable definitions */ -static unsigned long lib_stack_top_addr; -static unsigned long lib_stack_bot_addr; static unsigned long lib_stack_size; /* Function definitions */ @@ -60,11 +59,12 @@ int set_stack_params(unsigned long stack_top, } /* Arguments passed the validity tests. */ - /* Initialize internal variables */ - lib_stack_bot_addr = stack_bottom; - lib_stack_top_addr = stack_top; + /* Initialize internal variables. */ lib_stack_size = stack_size; + /* Init stack virtual address pool. */ + stack_pool_init(stack_top, stack_bottom, stack_size); + return 0; } @@ -75,6 +75,7 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, unsigned long utcb_addr; struct l4t_tcb *parent, *child; int err; + unsigned long stack_top_addr, stack_bot_addr; /* A few controls before granting access to thread creation */ // FIXME: check if utcb region is setup @@ -84,11 +85,7 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, 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 stack space // FIXME: Check if there is enough utcb space @@ -110,7 +107,7 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, return -ENOMEM; } - /* 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 @@ -128,9 +125,14 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, return err; } + /* Get a stack space and calculate the bottom addr of the stack. */ + stack_top_addr = (unsigned long)stack_new_space(1, lib_stack_size); + stack_bot_addr = stack_top_addr + lib_stack_size; + child->stack_addr = stack_top_addr; + /* 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); @@ -142,13 +144,11 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, } /* 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; @@ -174,6 +174,9 @@ void l4thread_kill(struct task_ids *ids) /* Delete the utcb address. */ delete_utcb_addr(task); + /* Delete the stack region. */ + stack_delete_space((void *)task->stack_addr, 1, lib_stack_size); + /* Remove child from the global task list. */ l4t_global_remove_task(task); diff --git a/conts/libl4thread/src/utcb-common.c b/conts/libl4thread/src/utcb-common.c index 38df843..4356be9 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 @@ -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 */ diff --git a/conts/libl4thread/src/utcb.c b/conts/libl4thread/src/utcb.c index 4dd7fef..2a20623 100644 --- a/conts/libl4thread/src/utcb.c +++ b/conts/libl4thread/src/utcb.c @@ -128,7 +128,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,7 +137,7 @@ int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end) } /* Arguments passed the validity tests. */ - /* Init utcb virtual address pool */ + /* Init utcb virtual address pool. */ utcb_pool_init(utcb_start, utcb_end); /* The very first thread's utcb address is assigned. */ From 9763296ddc1e79f507e508e581adb14b2b36f2af Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Wed, 11 Nov 2009 21:33:15 +0200 Subject: [PATCH 11/19] Locking is added to the thread library. Now, we support thread trees which are spanning more than one level depth. Any thread can create any number of threads provided that they are under the limits which are enforced by the kernel. Also with this commit, we have almost finished supporting SHARED space thread creation in which stack and utcb space are allocated statically. --- conts/libl4thread/include/l4thread/stack.h | 7 +- conts/libl4thread/include/l4thread/thread.h | 10 +- conts/libl4thread/src/arch-arm/new_thread.S | 5 +- conts/libl4thread/src/stack.c | 67 ++++++++++- conts/libl4thread/src/thread.c | 122 +++++++++++--------- conts/libl4thread/src/utcb.c | 2 +- 6 files changed, 144 insertions(+), 69 deletions(-) diff --git a/conts/libl4thread/include/l4thread/stack.h b/conts/libl4thread/include/l4thread/stack.h index d49a79a..6f382e2 100644 --- a/conts/libl4thread/include/l4thread/stack.h +++ b/conts/libl4thread/include/l4thread/stack.h @@ -6,11 +6,14 @@ #ifndef __LIB_STACK_H__ #define __LIB_STACK_H__ +/* Symbolic constants and macros */ +#define IS_STACK_SETUP() (lib_stack_size) + int stack_pool_init(unsigned long stack_start, unsigned long stack_end, unsigned long stack_size); -void *stack_new_space(int nitems, int size); -int stack_delete_space(void *stack_address, int nitems, int size); +void *get_stack_space(int nitems, int size); +int delete_stack_space(void *stack_address, int nitems, int size); #endif /* __LIB_STACK_H__ */ diff --git a/conts/libl4thread/include/l4thread/thread.h b/conts/libl4thread/include/l4thread/thread.h index 319233e..77246e3 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 (*func)(void *), void *arg); -void l4thread_kill(struct task_ids *ids); +int l4_thread_create(struct task_ids *ids, unsigned int flags, + void *(*func)(void *), void *arg); +void l4_thread_exit(void *retval); #endif /* __LIB_THREAD_H__ */ diff --git a/conts/libl4thread/src/arch-arm/new_thread.S b/conts/libl4thread/src/arch-arm/new_thread.S index 908569d..1014817 100644 --- a/conts/libl4thread/src/arch-arm/new_thread.S +++ b/conts/libl4thread/src/arch-arm/new_thread.S @@ -2,10 +2,11 @@ BEGIN_PROC(setup_new_thread) - ldr r0, [sp], #-4 @ Load first argument. + 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 @ We infinitely loop for now. + b new_thread_exit @ Never reaches here END_PROC(setup_new_thread) diff --git a/conts/libl4thread/src/stack.c b/conts/libl4thread/src/stack.c index a48de63..36b86b8 100644 --- a/conts/libl4thread/src/stack.c +++ b/conts/libl4thread/src/stack.c @@ -5,6 +5,15 @@ */ #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; @@ -26,12 +35,66 @@ int stack_pool_init(unsigned long stack_start, return 0; } -void *stack_new_space(int nitems, int size) +void *get_stack_space(int nitems, int size) { return address_new(&stack_region_pool, nitems, size); } -int stack_delete_space(void *stack_address, int nitems, int size) +int delete_stack_space(void *stack_address, int nitems, int size) { return address_del(&stack_region_pool, stack_address, nitems, size); } + +int l4_set_stack_params(unsigned long stack_top, + unsigned long stack_bottom, + unsigned long stack_size) +{ + /* Ensure that arguments are valid. */ + // FIXME: Check if lib_stack_size is convenient to use + // for ensuring stack space is setup. + 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; + + /* Init stack virtual address pool. */ + stack_pool_init(stack_top, stack_bottom, stack_size); + + /* Init the global mutex. */ + //FIXME: Ensure that l4thread_create will not be called + // before the mutex is initialized. + l4_mutex_init(&lib_mutex); + + return 0; +} + diff --git a/conts/libl4thread/src/thread.c b/conts/libl4thread/src/thread.c index c7f643b..d2f0c3e 100644 --- a/conts/libl4thread/src/thread.c +++ b/conts/libl4thread/src/thread.c @@ -5,71 +5,25 @@ */ #include #include +#include #include +#include #include #include #include #include #include -/* Symbolic constants and macros */ -#define IS_STACK_SETUP() (lib_stack_size) - /* Extern declarations */ extern void setup_new_thread(void); +extern unsigned long lib_stack_size; /* Static variable definitions */ -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_size = stack_size; - - /* Init stack virtual address pool. */ - stack_pool_init(stack_top, stack_bottom, stack_size); - - return 0; -} - -int l4thread_create(struct task_ids *ids, unsigned int flags, - int (*func)(void *), void *arg) +int l4_thread_create(struct task_ids *ids, unsigned int flags, + void *(*func)(void *), void *arg) { struct exregs_data exregs; unsigned long utcb_addr; @@ -96,6 +50,9 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, 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))) @@ -126,7 +83,7 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, } /* Get a stack space and calculate the bottom addr of the stack. */ - stack_top_addr = (unsigned long)stack_new_space(1, lib_stack_size); + stack_top_addr = (unsigned long)get_stack_space(1, lib_stack_size); stack_bot_addr = stack_top_addr + lib_stack_size; child->stack_addr = stack_top_addr; @@ -156,26 +113,37 @@ int l4thread_create(struct task_ids *ids, unsigned int flags, /* Start the new thread */ if ((err = l4_thread_control(THREAD_RUN, ids)) < 0) { + // FIXME: Check if there is any memory leak printf("libl4thread: l4_thread_control(THREAD_RUN) " "failed with (%d).\n", err); return err; } + /* Release the global mutex. */ + l4_mutex_unlock(&lib_mutex); + return 0; } -void l4thread_kill(struct task_ids *ids) +void l4_thread_exit(void *retval) { struct l4t_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 = l4t_find_task(ids.tid))) + BUG(); /* Delete the utcb address. */ delete_utcb_addr(task); /* Delete the stack region. */ - stack_delete_space((void *)task->stack_addr, 1, lib_stack_size); + delete_stack_space((void *)task->stack_addr, 1, lib_stack_size); /* Remove child from the global task list. */ l4t_global_remove_task(task); @@ -183,6 +151,46 @@ void l4thread_kill(struct task_ids *ids) // FIXME: We assume that main thread never leaves the scene kfree(task); + /* Release the global mutex. */ + l4_mutex_unlock(&lib_mutex); + + /* Relinquish the control. */ + l4_exit(*(unsigned int *)retval); + + /* Should never reach here. */ + BUG(); +} + +int l4_thread_kill(struct task_ids *ids) +{ + struct l4t_tcb *task; + + /* Before doing any operation get the global mutex. */ + l4_mutex_lock(&lib_mutex); + + /* Find the task to be killed. */ + if (!(task = l4t_find_task(ids->tid))) { + l4_mutex_unlock(&lib_mutex); + return -ESRCH; + } + + /* Delete the utcb address. */ + delete_utcb_addr(task); + + /* Delete the stack region. */ + delete_stack_space((void *)task->stack_addr, 1, lib_stack_size); + + /* Remove child from the global task list. */ + l4t_global_remove_task(task); + + // FIXME: We assume that main thread never leaves the scene + 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.c b/conts/libl4thread/src/utcb.c index 2a20623..8415ff8 100644 --- a/conts/libl4thread/src/utcb.c +++ b/conts/libl4thread/src/utcb.c @@ -97,7 +97,7 @@ static int set_utcb_addr(void) 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; From 58959d5fb0e92446db97e3c8d32ed5d6e9effad0 Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Thu, 12 Nov 2009 22:29:41 +0200 Subject: [PATCH 12/19] A comprehensive overhaul on the thread library. Lots of polishing, organizational changes, bug fixes, error handling etc. are introduced. COPY and NEW space thread creation are allowed but not thoroughly tested yet. It seems they will work best if the lib supports utcb virtual range management through the mapping. --- conts/libl4thread/include/l4thread/addr.h | 2 +- conts/libl4thread/include/l4thread/stack.h | 8 +- conts/libl4thread/include/l4thread/tcb.h | 21 ++- conts/libl4thread/include/l4thread/thread.h | 4 +- conts/libl4thread/include/l4thread/utcb.h | 9 +- conts/libl4thread/src/idpool.c | 3 +- conts/libl4thread/src/stack.c | 21 ++- conts/libl4thread/src/tcb.c | 38 +++--- conts/libl4thread/src/thread.c | 134 +++++++++++--------- conts/libl4thread/src/utcb-common.c | 8 +- conts/libl4thread/src/utcb.c | 60 +++++---- 11 files changed, 177 insertions(+), 131 deletions(-) diff --git a/conts/libl4thread/include/l4thread/addr.h b/conts/libl4thread/include/l4thread/addr.h index 900d790..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 */ diff --git a/conts/libl4thread/include/l4thread/stack.h b/conts/libl4thread/include/l4thread/stack.h index 6f382e2..d0e5f09 100644 --- a/conts/libl4thread/include/l4thread/stack.h +++ b/conts/libl4thread/include/l4thread/stack.h @@ -1,19 +1,19 @@ /* - * Stack region helper routines. + * Stack space helper routines. * * Copyright (C) 2009 B Labs Ltd. */ #ifndef __LIB_STACK_H__ #define __LIB_STACK_H__ -/* Symbolic constants and macros */ +/* 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(int nitems, int size); -int delete_stack_space(void *stack_address, int nitems, int 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 a2f399e..da332e0 100644 --- a/conts/libl4thread/include/l4thread/tcb.h +++ b/conts/libl4thread/include/l4thread/tcb.h @@ -14,23 +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 77246e3..8cd3125 100644 --- a/conts/libl4thread/include/l4thread/thread.h +++ b/conts/libl4thread/include/l4thread/thread.h @@ -12,7 +12,7 @@ int l4_set_stack_params(unsigned long stack_top, int l4_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end); int l4_thread_create(struct task_ids *ids, unsigned int flags, - void *(*func)(void *), void *arg); -void l4_thread_exit(void *retval); + int (*func)(void *), void *arg); +void l4_thread_exit(int retval); #endif /* __LIB_THREAD_H__ */ 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/idpool.c b/conts/libl4thread/src/idpool.c index 423ac33..17fd450 100644 --- a/conts/libl4thread/src/idpool.c +++ b/conts/libl4thread/src/idpool.c @@ -1,5 +1,6 @@ /* - * Used for thread and space ids, and also for utcbs. + * Used for thread and space ids, and also for + * utcb tracking in page-sized-chunks. * * Copyright (C) 2009 B Labs Ltd. */ diff --git a/conts/libl4thread/src/stack.c b/conts/libl4thread/src/stack.c index 36b86b8..5fedcba 100644 --- a/conts/libl4thread/src/stack.c +++ b/conts/libl4thread/src/stack.c @@ -35,14 +35,14 @@ int stack_pool_init(unsigned long stack_start, return 0; } -void *get_stack_space(int nitems, int size) +void *get_stack_space(void) { - return address_new(&stack_region_pool, nitems, size); + return address_new(&stack_region_pool, 1, lib_stack_size); } -int delete_stack_space(void *stack_address, int nitems, int size) +int delete_stack_space(void *stack_address) { - return address_del(&stack_region_pool, stack_address, nitems, size); + return address_del(&stack_region_pool, stack_address, 1, lib_stack_size); } int l4_set_stack_params(unsigned long stack_top, @@ -50,11 +50,9 @@ int l4_set_stack_params(unsigned long stack_top, unsigned long stack_size) { /* Ensure that arguments are valid. */ - // FIXME: Check if lib_stack_size is convenient to use - // for ensuring stack space is setup. if (IS_STACK_SETUP()) { printf("libl4thread: You have already called: %s.\n", - __FUNCTION__); + __FUNCTION__); return -EPERM; } if (!stack_top || !stack_bottom) { @@ -87,12 +85,11 @@ int l4_set_stack_params(unsigned long stack_top, /* Initialize internal variables. */ lib_stack_size = stack_size; - /* Init stack virtual address pool. */ - stack_pool_init(stack_top, stack_bottom, stack_size); + /* Initialize stack virtual address pool. */ + if (stack_pool_init(stack_top, stack_bottom, stack_size) < 0) + BUG(); - /* Init the global mutex. */ - //FIXME: Ensure that l4thread_create will not be called - // before the mutex is initialized. + /* 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 d2f0c3e..61b0f53 100644 --- a/conts/libl4thread/src/thread.c +++ b/conts/libl4thread/src/thread.c @@ -17,76 +17,70 @@ /* Extern declarations */ extern void setup_new_thread(void); extern unsigned long lib_stack_size; +extern unsigned long lib_utcb_range_size; /* Static variable definitions */ struct l4_mutex lib_mutex; /* Function definitions */ int l4_thread_create(struct task_ids *ids, unsigned int flags, - void *(*func)(void *), void *arg) + 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; } - // FIXME: Check if there is enough stack space - - // 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. */ 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; } - /* Get a stack space and calculate the bottom addr of the stack. */ - stack_top_addr = (unsigned long)get_stack_space(1, lib_stack_size); - stack_bot_addr = stack_top_addr + lib_stack_size; - child->stack_addr = stack_top_addr; - /* Setup new thread pc, sp, utcb */ memset(&exregs, 0, sizeof(exregs)); exregs_set_stack(&exregs, align((stack_bot_addr - 1), 8)); @@ -95,9 +89,8 @@ int l4_thread_create(struct task_ids *ids, unsigned int flags, 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 */ @@ -109,25 +102,42 @@ int l4_thread_create(struct task_ids *ids, unsigned int flags, /* 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) { - // FIXME: Check if there is any memory leak 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 l4_thread_exit(void *retval) +void l4_thread_exit(int retval) { - struct l4t_tcb *task; + struct tcb *task; struct task_ids ids; /* Before doing any operation get the global mutex. */ @@ -136,26 +146,28 @@ void l4_thread_exit(void *retval) /* Find the task. */ l4_getid(&ids); /* Cant find the thread means it wasnt added to the list. */ - if (!(task = l4t_find_task(ids.tid))) + 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); - /* Delete the stack region. */ - delete_stack_space((void *)task->stack_addr, 1, lib_stack_size); - - /* Remove child from the global task list. */ - l4t_global_remove_task(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(*(unsigned int *)retval); + l4_exit(retval); /* Should never reach here. */ BUG(); @@ -163,27 +175,29 @@ void l4_thread_exit(void *retval) int l4_thread_kill(struct task_ids *ids) { - struct l4t_tcb *task; + struct tcb *task; /* Before doing any operation get the global mutex. */ l4_mutex_lock(&lib_mutex); /* Find the task to be killed. */ - if (!(task = l4t_find_task(ids->tid))) { + if (!(task = find_task(ids->tid))) { l4_mutex_unlock(&lib_mutex); return -ESRCH; } + /* 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); - /* Delete the stack region. */ - delete_stack_space((void *)task->stack_addr, 1, lib_stack_size); - - /* Remove child from the global task list. */ - l4t_global_remove_task(task); - // FIXME: We assume that main thread never leaves the scene + // FIXME: What happens to task->utcb_head? kfree(task); /* Release the global mutex. */ diff --git a/conts/libl4thread/src/utcb-common.c b/conts/libl4thread/src/utcb-common.c index 4356be9..5ad511a 100644 --- a/conts/libl4thread/src/utcb-common.c +++ b/conts/libl4thread/src/utcb-common.c @@ -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; } @@ -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 8415ff8..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,29 +72,31 @@ 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; } @@ -102,21 +108,20 @@ 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. */ @@ -138,11 +143,18 @@ int l4_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); + 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; } From 7fb923cd35ebae674d74e0f57abaff367f89441f Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Mon, 16 Nov 2009 19:06:45 +0200 Subject: [PATCH 13/19] A workaround for an unmatched locker-unlocker mutex problem. If sleepers on a mutex were more than one, only one of them was woken up. This caused the other ones to sleep forever. Now, there is not any facility to check if there are still sleepers on the kernel space when a thread is about to unlock a mutex. To workaround this problem, we started waking up all the threads instead of one. This brings another problem called thundering herd but also provides random fairness which gives more oppurtunity to a higher priority thread to get the lock. --- src/api/mutex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/mutex.c b/src/api/mutex.c index d17fed3..829d190 100644 --- a/src/api/mutex.c +++ b/src/api/mutex.c @@ -210,7 +210,7 @@ int mutex_control_unlock(struct mutex_queue_head *mqhead, * now wake all of them up in FIFO order. * FIXME: Make sure this is FIFO order. It doesn't seem so. */ - wake_up(&mutex_queue->wqh_contenders, WAKEUP_ASYNC); + wake_up_all(&mutex_queue->wqh_contenders, WAKEUP_ASYNC); /* Since noone is left, delete the mutex queue */ mutex_control_remove(mqhead, mutex_queue); From 682c62f8bb086eb4f5f38ed601ab261c0a103973 Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Mon, 16 Nov 2009 21:49:37 +0200 Subject: [PATCH 14/19] A fix and a helper macro for the thread library. The fix solves the problem of giving the last slice from a pool. The helper macro makes utcb space creation easy for the user because we have to consider a few things like alignment and total allocated space. --- conts/libl4thread/include/l4thread/thread.h | 4 ++++ conts/libl4thread/src/bit.c | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/conts/libl4thread/include/l4thread/thread.h b/conts/libl4thread/include/l4thread/thread.h index 8cd3125..7afe124 100644 --- a/conts/libl4thread/include/l4thread/thread.h +++ b/conts/libl4thread/include/l4thread/thread.h @@ -6,6 +6,10 @@ #ifndef __LIB_THREAD_H__ #define __LIB_THREAD_H__ +/* A helper macro easing utcb space creation. */ +#define DECLARE_UTCB_SPACE(name, entries) \ + char name[(entries + PAGE_SIZE / UTCB_SIZE) * UTCB_SIZE] ALIGN(PAGE_SIZE); + int l4_set_stack_params(unsigned long stack_top, unsigned long stack_bottom, unsigned long stack_size); diff --git a/conts/libl4thread/src/bit.c b/conts/libl4thread/src/bit.c index b021211..7c0ab4e 100644 --- a/conts/libl4thread/src/bit.c +++ b/conts/libl4thread/src/bit.c @@ -49,8 +49,7 @@ int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit, return -1; /* This is a state machine that checks n contiguous free bits. */ - /* FIXME: It should be <= instead of <. Fix & test in a single patch */ - while (i + nbits < limit) { + while (i + nbits <= limit) { first = i; last = i; while (!(word[BITWISE_GETWORD(last)] & BITWISE_GETBIT(last))) { From a5eede8fb94749e510d1d6097844ba1b015acc6e Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Tue, 17 Nov 2009 12:05:56 +0200 Subject: [PATCH 15/19] The very same fix we applied to the thread library but for posix this time. --- conts/posix/mm0/lib/bit.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/conts/posix/mm0/lib/bit.c b/conts/posix/mm0/lib/bit.c index 84750e3..6c1688b 100644 --- a/conts/posix/mm0/lib/bit.c +++ b/conts/posix/mm0/lib/bit.c @@ -51,8 +51,7 @@ int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit, return -1; /* This is a state machine that checks n contiguous free bits. */ - /* FIXME: It should be <= instead of <. Fix & test in a single patch */ - while (i + nbits < limit) { + while (i + nbits <= limit) { first = i; last = i; while (!(word[BITWISE_GETWORD(last)] & BITWISE_GETBIT(last))) { From 7387d336ccf8ea5f2c06b2d831029df9f805a14d Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Tue, 17 Nov 2009 18:13:32 +0200 Subject: [PATCH 16/19] Thread waiting is fixed. In the former case, when a child was exiting there was a risk of being preempted while it was also taken away from the runqueue. In this situatuion, it may not have had the chance of waking up the parent in case if it waits for the child to exit. This was also true for suspend & resume so they were patched also. --- src/generic/scheduler.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/generic/scheduler.c b/src/generic/scheduler.c index f6934f0..4f88fd2 100644 --- a/src/generic/scheduler.c +++ b/src/generic/scheduler.c @@ -233,10 +233,10 @@ void sched_exit_sync(void) sched_rq_remove_task(current); current->state = TASK_DEAD; current->flags &= ~TASK_EXITING; - preempt_enable(); if (current->pagerid != current->tid) wake_up(¤t->wqh_pager, 0); + preempt_enable(); schedule(); } @@ -247,10 +247,10 @@ void sched_exit_async(void) sched_rq_remove_task(current); current->state = TASK_DEAD; current->flags &= ~TASK_EXITING; - preempt_enable(); if (current->pagerid != current->tid) wake_up(¤t->wqh_pager, 0); + preempt_enable(); need_resched = 1; } @@ -265,10 +265,10 @@ void sched_suspend_sync(void) sched_rq_remove_task(current); current->state = TASK_INACTIVE; current->flags &= ~TASK_SUSPENDING; - preempt_enable(); if (current->pagerid != current->tid) wake_up(¤t->wqh_pager, 0); + preempt_enable(); schedule(); } @@ -279,10 +279,10 @@ void sched_suspend_async(void) sched_rq_remove_task(current); current->state = TASK_INACTIVE; current->flags &= ~TASK_SUSPENDING; - preempt_enable(); if (current->pagerid != current->tid) wake_up(¤t->wqh_pager, 0); + preempt_enable(); need_resched = 1; } From b2a2340594415c656a6f7b6645dd0d959dd7fbc0 Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Tue, 17 Nov 2009 20:44:42 +0200 Subject: [PATCH 17/19] Clean dcache CP0 instruction is corrected. Possibly it was caused by a typo. --- src/arch/arm/v5/mmu_ops.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arch/arm/v5/mmu_ops.S b/src/arch/arm/v5/mmu_ops.S index eb6d9da..ceda880 100644 --- a/src/arch/arm/v5/mmu_ops.S +++ b/src/arch/arm/v5/mmu_ops.S @@ -105,7 +105,7 @@ BEGIN_PROC(arm_invalidate_dcache) END_PROC(arm_invalidate_dcache) BEGIN_PROC(arm_clean_dcache) - mcr p15, 0 , pc, c7, c10, 3 @ Test/clean dcache line + mrc p15, 0 , pc, c7, c10, 3 @ Test/clean dcache line bne arm_clean_dcache mcr p15, 0, ip, c7, c10, 4 @ Drain WB mov pc, lr From 9a8e1fa4376d50da5db3bab01823293b6e15864c Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Tue, 17 Nov 2009 21:20:09 +0200 Subject: [PATCH 18/19] A few things needed in the destroy code paths of a thread are added. The first one is related to resource recycling. The parent which is waiting its child to exit did not delete its ktcb. Now, it deletes. The second one is related to self destroy. The added code wakes up all the waiters before it exits. --- src/api/thread.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/api/thread.c b/src/api/thread.c index 618a16d..1da38c3 100644 --- a/src/api/thread.c +++ b/src/api/thread.c @@ -105,12 +105,18 @@ int thread_destroy_children(void) void thread_destroy_self(unsigned int exit_code) { thread_destroy_children(); + + /* Wake up waiters */ + wake_up_all(¤t->wqh_send, WAKEUP_INTERRUPT); + wake_up_all(¤t->wqh_recv, WAKEUP_INTERRUPT); + current->exit_code = exit_code; sched_exit_sync(); } int thread_wait(struct ktcb *task) { + unsigned int exit_code; int ret; /* Wait until task switches to desired state */ @@ -118,8 +124,12 @@ int thread_wait(struct ktcb *task) task->state == TASK_DEAD, ret); if (ret < 0) return ret; - else - return (int)task->exit_code; + else { + exit_code = (int)task->exit_code; + tcb_remove(task); + tcb_delete(task); + return exit_code; + } } int thread_destroy(struct ktcb *task, unsigned int exit_code) From 496fba81c804bf95e32bde9d7a58e7db773c46a8 Mon Sep 17 00:00:00 2001 From: Bora Sahin Date: Tue, 17 Nov 2009 21:48:46 +0200 Subject: [PATCH 19/19] A shared space multi-threaded example application presenting the use of the thread library. It also exemplifies how a new sample application can be added. --- config/cml/container_ruleset.template | 4 +- conts/examples/example2/SConstruct | 67 +++++++++++++++ conts/examples/example2/container.c | 21 +++++ conts/examples/example2/main.c | 116 ++++++++++++++++++++++++++ 4 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 conts/examples/example2/SConstruct create mode 100644 conts/examples/example2/container.c create mode 100644 conts/examples/example2/main.c diff --git a/config/cml/container_ruleset.template b/config/cml/container_ruleset.template index d06580f..1e4a58f 100644 --- a/config/cml/container_ruleset.template +++ b/config/cml/container_ruleset.template @@ -133,12 +133,14 @@ cont%(cn)d_posix_pager_params 'Container %(cn)d POSIX Pager Parameters' cont%(cn)d_examples_params 'Example Applications List' CONT%(cn)d_EXAMPLE_APP0 'Empty Application' -CONT%(cn)d_EXAMPLE_APP1 'Hello world' +CONT%(cn)d_EXAMPLE_APP1 'Hello World' +CONT%(cn)d_EXAMPLE_APP2 'Thread Library Demo' choices cont%(cn)d_examples_params CONT%(cn)d_EXAMPLE_APP0 CONT%(cn)d_EXAMPLE_APP1 + CONT%(cn)d_EXAMPLE_APP2 default CONT%(cn)d_EXAMPLE_APP0 menu cont%(cn)d_default_pager_params diff --git a/conts/examples/example2/SConstruct b/conts/examples/example2/SConstruct new file mode 100644 index 0000000..63134bb --- /dev/null +++ b/conts/examples/example2/SConstruct @@ -0,0 +1,67 @@ +# -*- mode: python; coding: utf-8; -*- +# +# Codezero -- Virtualization microkernel for embedded systems. +# +# Copyright © 2009 B Labs Ltd +# +import os, shelve, sys +from os.path import * + +PROJRELROOT = '../..' + +sys.path.append(PROJRELROOT) + +from config.projpaths import * +from config.configuration import * + + +config = configuration_retrieve() + +arch = config.arch + +LIBL4_RELDIR = 'conts/libl4' +KERNEL_INCLUDE = join(PROJROOT, 'include') +LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR) +LIBL4_INCLUDE = join(LIBL4_DIR, 'include') +LIBL4_LIBPATH = join(BUILDDIR, LIBL4_RELDIR) + +# Locally important paths are here +LIBC_RELDIR = 'conts/libc' +LIBC_DIR = join(PROJROOT, LIBC_RELDIR) +LIBC_LIBPATH = join(BUILDDIR, LIBC_RELDIR) +LIBC_INCLUDE = [join(LIBC_DIR, 'include'), \ + join(LIBC_DIR, 'include/arch' + '/' + arch)] + +LIBL4THREAD_RELDIR = 'conts/libl4thread' +LIBL4THREAD_DIR = join(PROJROOT, LIBL4THREAD_RELDIR) +LIBL4THREAD_LIBPATH = join(BUILDDIR, LIBL4THREAD_RELDIR) +LIBL4THREAD_INCLUDE = join(LIBL4THREAD_DIR, 'include') + +LIBMEM_RELDIR = 'conts/libmem' +LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR) +LIBMEM_LIBPATH = join(BUILDDIR, LIBMEM_RELDIR) +LIBMEM_INCLUDE = LIBMEM_DIR + +env = Environment(CC = 'arm-none-linux-gnueabi-gcc', + # We don't use -nostdinc because sometimes we need standard headers, + # such as stdarg.h e.g. for variable args, as in printk(). + CCFLAGS = ['-g', '-mcpu=arm926ej-s', '-nostdlib', '-ffreestanding', \ + '-std=gnu99', '-Wall', '-Werror'], + LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"], + ASFLAGS = ['-D__ASSEMBLY__'], + PROGSUFFIX = '.elf', # The suffix to use for final executable + ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path + LIBS = ['libl4thread', 'libl4', 'libmalloc', 'c-userspace', \ + 'gcc', 'c-userspace'], # libgcc.a - This is required for division routines. + CPPPATH = ["#include", KERNEL_INCLUDE, LIBL4_INCLUDE, LIBC_INCLUDE, \ + LIBL4THREAD_INCLUDE], + LIBPATH = [LIBL4_LIBPATH, LIBC_LIBPATH, LIBL4THREAD_LIBPATH, \ + LIBMEM_LIBPATH], + CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h') + +src = Glob('*.[cS]') +src += Glob('src/*.[cS]') + +objs = env.Object(src) +prog = env.Program('main.elf', objs) +Depends(prog, 'include/linker.lds') diff --git a/conts/examples/example2/container.c b/conts/examples/example2/container.c new file mode 100644 index 0000000..f570c3d --- /dev/null +++ b/conts/examples/example2/container.c @@ -0,0 +1,21 @@ +/* + * Container entry point for pager + * + * Copyright (C) 2007-2009 B Labs Ltd. + */ + +#include +#include + + +extern void main(void); + +void __container_init(void) +{ + /* Generic L4 initialisation */ + __l4_init(); + + /* Entry to main */ + main(); +} + diff --git a/conts/examples/example2/main.c b/conts/examples/example2/main.c new file mode 100644 index 0000000..272021e --- /dev/null +++ b/conts/examples/example2/main.c @@ -0,0 +1,116 @@ +/* + * Main function for this container + */ +#include +#include +#include +#include + +/* Symbolic constants */ +#define STACK_SIZE 0x1000 +#define NTHREADS 10 + +/* Stack and utcb region */ +static char stack[NTHREADS * STACK_SIZE]; +DECLARE_UTCB_SPACE(utcb, NTHREADS) + +/* Function definitions */ +static void init_thread_lib(void) +{ + /* Thread lib is informed about the stack region. */ + l4_set_stack_params((unsigned long)stack, + (unsigned long)(stack + sizeof(stack)), + STACK_SIZE); + + /* Thread lib is informed about the utcb region. */ + l4_set_utcb_params((unsigned long)utcb, + (unsigned long)(utcb + sizeof(utcb))); + + /* Now, we are ready to make calls to the library. */ +} + +static int do_some_work1(void *arg) +{ + struct task_ids ids; + int value = *(int *)arg; + int j; + + l4_getid(&ids); + printf("tid = %d is called with the value of (%d).\n", + __raw_tid(ids.tid), value); + + /* Wait for a while before exiting */ + j = 0x400000; + while (--j) + ; + + return ids.tid; +} + +static int do_some_work2(void *arg) +{ + struct task_ids ids; + int value = *(int *)arg; + int j; + + l4_getid(&ids); + printf("tid = %d is called with the value of (%d).\n", + __raw_tid(ids.tid), value); + + /* Wait for a while before exiting */ + j = 0x400000; + while (--j) + ; + + l4_thread_exit(ids.tid); + + /* Should never reach here */ + return 0; +} + +static int thread_demo(void) +{ + struct task_ids ids[NTHREADS]; + int arg[NTHREADS]; + int j; + + memset(ids, 0, sizeof(ids)); + + /* Create threads. */ + for (int i = 0; i < NTHREADS; ++i) { + /* The argument passed to the thread in question. */ + arg[i] = i; + + /* Threads are created. */ + if (i % 2) + l4_thread_create(&ids[i], TC_SHARE_SPACE | TC_SHARE_PAGER, + do_some_work1, (void *)&arg[i]); + else + l4_thread_create(&ids[i], TC_SHARE_SPACE | TC_SHARE_PAGER, + do_some_work2, (void *)&arg[i]); + + /* Wait for a while before launching another thread. */ + j = 0x100000; + while (--j) + ; + } + + /* Wait for them to exit. */ + for (int i = 0; i < NTHREADS; ++i) + printf("tid = %d exited with (%d).\n", __raw_tid(ids[i].tid), + l4_thread_control(THREAD_WAIT, &ids[i])); + + return 0; +} + +int main(void) +{ + /* Before using the thread lib, we have to initialize it. */ + init_thread_lib(); + + /* Demonstrates the usage of the thread lib. */ + thread_demo(); + + return 0; +} +