Merge branch 'libl4thread' of git://www.b-labs.co.uk/bora/git/codezero into bora

Conflicts:
	conts/libl4thread/src/arch-arm/new_thread.S
	conts/libl4thread/src/idpool.c
This commit is contained in:
Bahadir Balban
2009-11-19 11:17:51 +02:00
14 changed files with 453 additions and 178 deletions

View File

@@ -1,5 +1,5 @@
/* /*
* Address allocation pool * Address allocation pool.
* *
* Copyright (C) 2007 Bahadir Balban * Copyright (C) 2007 Bahadir Balban
*/ */
@@ -21,7 +21,7 @@ int address_pool_init_with_idpool(struct address_pool *pool,
int address_pool_init(struct address_pool *pool, int address_pool_init(struct address_pool *pool,
unsigned long start, unsigned long end, unsigned long start, unsigned long end,
int size); int size);
void *address_new(struct address_pool *pool, int npages); void *address_new(struct address_pool *pool, int nitems, int size);
int address_del(struct address_pool *, void *addr, int npages); int address_del(struct address_pool *, void *addr, int nitems, int size);
#endif /* __ADDR_H__ */ #endif /* __ADDR_H__ */

View File

@@ -0,0 +1,19 @@
/*
* Stack space helper routines.
*
* Copyright (C) 2009 B Labs Ltd.
*/
#ifndef __LIB_STACK_H__
#define __LIB_STACK_H__
/* Checks if l4_set_stack_params is called. */
#define IS_STACK_SETUP() (lib_stack_size)
int stack_pool_init(unsigned long stack_start,
unsigned long stack_end,
unsigned long stack_size);
void *get_stack_space(void);
int delete_stack_space(void *stack_address);
#endif /* __LIB_STACK_H__ */

View File

@@ -14,22 +14,30 @@ struct utcb_head {
}; };
/* A simple thread control block for the thread library. */ /* A simple thread control block for the thread library. */
struct l4t_tcb { struct tcb {
/* Task list */
struct link list; struct link list;
/* Task id */
int tid; int tid;
/* Chain of utcb descriptors */
struct utcb_head *utcb_head; struct utcb_head *utcb_head;
/* Stack and utcb address */
unsigned long utcb_addr; unsigned long utcb_addr;
unsigned long stack_addr;
}; };
/* This struct keeps track of all the threads handled by the thread lib. */ /* All the threads handled by the thread lib are kept in this list. */
struct l4t_global_list { struct global_list {
int total; int total;
struct link list; struct link list;
}; };
struct l4t_tcb *l4t_find_task(int tid); struct tcb *find_task(int tid);
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);
void l4t_global_add_task(struct l4t_tcb *task); void global_add_task(struct tcb *task);
void l4t_global_remove_task(struct l4t_tcb *task); void global_remove_task(struct tcb *task);
#endif /* __LIB_TCB_H__ */ #endif /* __LIB_TCB_H__ */

View File

@@ -6,13 +6,13 @@
#ifndef __LIB_THREAD_H__ #ifndef __LIB_THREAD_H__
#define __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_bottom,
unsigned long stack_size); unsigned long stack_size);
int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end); int l4_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end);
int l4thread_create(struct task_ids *ids, unsigned int flags, int l4_thread_create(struct task_ids *ids, unsigned int flags,
int (*func)(void *), void *arg); int (*func)(void *), void *arg);
void l4thread_kill(struct task_ids *ids); void l4_thread_exit(int retval);
#endif /* __LIB_THREAD_H__ */ #endif /* __LIB_THREAD_H__ */

View File

@@ -1,5 +1,5 @@
/* /*
* UTCB handling common helper routines * UTCB handling common helper routines.
* *
* Copyright (C) 2009 B Labs Ltd. * Copyright (C) 2009 B Labs Ltd.
*/ */

View File

@@ -1,5 +1,5 @@
/* /*
* UTCB handling helper routines * UTCB handling helper routines.
* *
* Copyright (C) 2009 B Labs Ltd. * Copyright (C) 2009 B Labs Ltd.
*/ */
@@ -8,7 +8,10 @@
#include <tcb.h> #include <tcb.h>
unsigned long get_utcb_addr(struct l4t_tcb *task); /* Checks if l4_set_stack_params is called. */
int delete_utcb_addr(struct l4t_tcb *task); #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__ */ #endif /* __LIB_UTCB_H__ */

View File

@@ -33,21 +33,21 @@ int address_pool_init(struct address_pool *pool,
return 0; 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 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 " printf("%s: Invalid address range returned to "
"virtual address pool.\n", __FUNCTION__); "virtual address pool.\n", __FUNCTION__);
return -1; return -1;

View File

@@ -0,0 +1,12 @@
#include <l4lib/arch/asm.h>
BEGIN_PROC(setup_new_thread)
ldr r0, [sp], #-4 @ Load first argument
mov lr, pc @ Save return address
ldr pc, [sp], #-4 @ Load function pointer from stack
b l4_thread_exit @ Call l4_thread_exit for cleanup
new_thread_exit:
b new_thread_exit @ Never reaches here
END_PROC(setup_new_thread)

View File

@@ -0,0 +1,87 @@
/*
* Used for thread and space ids, and also for
* utcb tracking in page-sized-chunks.
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <idpool.h>
#include <stdio.h>
#include <l4/api/errno.h>
#include <malloc/malloc.h>
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;
}

View File

@@ -0,0 +1,97 @@
/*
* Stack management in libl4thread.
*
* Copyright © 2009 B Labs Ltd.
*/
#include <stdio.h>
#include <addr.h>
#include <l4/api/errno.h>
#include <l4lib/mutex.h>
#include <stack.h>
/* Extern declarations */
extern struct l4_mutex lib_mutex;
/* Global variables */
unsigned long lib_stack_size;
/* Stack virtual region pool */
static struct address_pool stack_region_pool;
int stack_pool_init(unsigned long stack_start,
unsigned long stack_end,
unsigned long stack_size)
{
int err;
/* Initialise the global stack virtual address pool. */
if ((err = address_pool_init(&stack_region_pool,
stack_start, stack_end,
stack_size) < 0)) {
printf("Stack address pool initialisation failed.\n");
return err;
}
return 0;
}
void *get_stack_space(void)
{
return address_new(&stack_region_pool, 1, lib_stack_size);
}
int delete_stack_space(void *stack_address)
{
return address_del(&stack_region_pool, stack_address, 1, lib_stack_size);
}
int l4_set_stack_params(unsigned long stack_top,
unsigned long stack_bottom,
unsigned long stack_size)
{
/* Ensure that arguments are valid. */
if (IS_STACK_SETUP()) {
printf("libl4thread: You have already called: %s.\n",
__FUNCTION__);
return -EPERM;
}
if (!stack_top || !stack_bottom) {
printf("libl4thread: Stack address range cannot contain "
"0x0 as a start and/or end address(es).\n");
return -EINVAL;
}
// FIXME: Aligning should be taken into account.
/*
* Stack grows downward so the top of the stack will have
* the lowest numbered address.
*/
if (stack_top >= stack_bottom) {
printf("libl4thread: Stack bottom address must be bigger "
"than stack top address.\n");
return -EINVAL;
}
if (!stack_size) {
printf("libl4thread: Stack size cannot be zero.\n");
return -EINVAL;
}
/* stack_size at least must be equal to the difference. */
if ((stack_bottom - stack_top) < stack_size) {
printf("libl4thread: The given range size is lesser than "
"the stack size(0x%x).\n", stack_size);
return -EINVAL;
}
/* Arguments passed the validity tests. */
/* Initialize internal variables. */
lib_stack_size = stack_size;
/* Initialize stack virtual address pool. */
if (stack_pool_init(stack_top, stack_bottom, stack_size) < 0)
BUG();
/* Initialize the global mutex. */
l4_mutex_init(&lib_mutex);
return 0;
}

View File

@@ -1,3 +1,8 @@
/*
* Thread management in libl4thread.
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <stdio.h> #include <stdio.h>
#include <malloc/malloc.h> #include <malloc/malloc.h>
#include <l4/api/errno.h> #include <l4/api/errno.h>
@@ -5,50 +10,53 @@
#include <tcb.h> #include <tcb.h>
/* Global task list. */ /* Global task list. */
struct l4t_global_list l4t_global_tasks = { struct global_list global_tasks = {
.list = { &l4t_global_tasks.list, &l4t_global_tasks.list }, .list = { &global_tasks.list, &global_tasks.list },
.total = 0, .total = 0,
}; };
/* Function definitions */ /* Function definitions */
void l4t_global_add_task(struct l4t_tcb *task) void global_add_task(struct tcb *task)
{ {
BUG_ON(!list_empty(&task->list)); BUG_ON(!list_empty(&task->list));
list_insert_tail(&task->list, &l4t_global_tasks.list); list_insert_tail(&task->list, &global_tasks.list);
l4t_global_tasks.total++; 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)); BUG_ON(list_empty(&task->list));
list_remove_init(&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) if (t->tid == tid)
return t; return t;
return 0; 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); return PTR_ERR(-ENOMEM);
link_init(&task->list); link_init(&task->list);
if ((parent) && (flags & TC_SHARE_SPACE)) if (flags & TC_SHARE_SPACE)
task->utcb_head = parent->utcb_head; task->utcb_head = parent->utcb_head;
else { 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); return PTR_ERR(-ENOMEM);
}
link_init(&task->utcb_head->list); link_init(&task->utcb_head->list);
} }

View File

@@ -5,181 +5,206 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <l4lib/arch/syscalls.h> #include <l4lib/arch/syscalls.h>
#include <l4lib/arch/syslib.h>
#include <l4lib/exregs.h> #include <l4lib/exregs.h>
#include <l4lib/mutex.h>
#include <l4/api/thread.h> #include <l4/api/thread.h>
#include <l4/api/errno.h> #include <l4/api/errno.h>
#include <malloc/malloc.h> #include <malloc/malloc.h>
#include <utcb.h> #include <utcb.h>
#include <stack.h>
/* Symbolic constants and macros */
#define IS_STACK_SETUP() (lib_stack_size)
/* Extern declarations */ /* Extern declarations */
extern void setup_new_thread(void); extern void setup_new_thread(void);
extern unsigned long lib_stack_size;
extern unsigned long lib_utcb_range_size;
/* Static variable definitions */ /* Static variable definitions */
static unsigned long lib_stack_top_addr; struct l4_mutex lib_mutex;
static unsigned long lib_stack_bot_addr;
static unsigned long lib_stack_size;
/* Function definitions */ /* Function definitions */
int set_stack_params(unsigned long stack_top, int l4_thread_create(struct task_ids *ids, unsigned int flags,
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) int (*func)(void *), void *arg)
{ {
struct exregs_data exregs; struct exregs_data exregs;
unsigned long utcb_addr; unsigned long utcb_addr;
struct l4t_tcb *parent, *child; struct tcb *parent, *child;
int err; unsigned long stack_top_addr, stack_bot_addr;
int err = 0;
/* A few controls before granting access to thread creation */ /* A few controls before granting access to thread creation */
// FIXME: check if utcb region is setup if (!IS_STACK_SETUP() || !IS_UTCB_SETUP()) {
if (!IS_STACK_SETUP()) {
printf("libl4thread: Stack and/or utcb have not been " printf("libl4thread: Stack and/or utcb have not been "
"set up.\n"); "set up.\n");
return -EPERM; return -EPERM;
} }
/* Is there enough stack space for the new thread? */ /* Before doing any operation get the global mutex. */
if (lib_stack_top_addr >= lib_stack_bot_addr) { l4_mutex_lock(&lib_mutex);
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. */ /* Get parent's ids and find the tcb belonging to it. */
l4_getid(ids); l4_getid(ids);
if (!(parent = l4t_find_task(ids->tid))) if (!(parent = find_task(ids->tid))) {
return-ESRCH; err = -ESRCH;
goto out_err1;
}
/* Allocate tcb for the child. */ /* 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"); printf("libl4thread: No heap space left.\n");
return -ENOMEM; err = -ENOMEM;
goto out_err1;
} }
/* Get a utcb addr for this thread */ /* Get a utcb addr. */
if (!(utcb_addr = get_utcb_addr(child))) { if (!(utcb_addr = get_utcb_addr(child))) {
printf("libl4thread: No utcb address left.\n"); printf("libl4thread: No utcb space left.\n");
// FIXME: Check if there is any memory leak err = -ENOMEM;
kfree(child); goto out_err2;
return -ENOMEM;
} }
/* 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 */ /* Create thread */
if ((err = l4_thread_control(THREAD_CREATE | flags, ids)) < 0) { if ((err = l4_thread_control(THREAD_CREATE | flags, ids)) < 0) {
printf("libl4thread: l4_thread_control(THREAD_CREATE) " printf("libl4thread: l4_thread_control(THREAD_CREATE) "
"failed with (%d).\n", err); "failed with (%d).\n", err);
// FIXME: Check if there is any memory leak goto out_err4;
kfree(child);
delete_utcb_addr(child);
return err;
} }
/* Setup new thread pc, sp, utcb */ /* Setup new thread pc, sp, utcb */
memset(&exregs, 0, sizeof(exregs)); 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_pc(&exregs, (unsigned long)setup_new_thread);
exregs_set_utcb(&exregs, (unsigned long)utcb_addr); exregs_set_utcb(&exregs, (unsigned long)utcb_addr);
if ((err = l4_exchange_registers(&exregs, ids->tid)) < 0) { if ((err = l4_exchange_registers(&exregs, ids->tid)) < 0) {
printf("libl4thread: l4_exchange_registers failed with " printf("libl4thread: l4_exchange_registers failed with "
"(%d).\n", err); "(%d).\n", err);
// FIXME: Check if there is any memory leak goto out_err5;
return err;
} }
/* First word of new stack is arg */ /* First word of new stack is arg */
((unsigned long *)align((lib_stack_bot_addr - 1), 8))[0] = ((unsigned long *)align((stack_bot_addr - 1), 8))[0] =
(unsigned long)arg; (unsigned long)arg;
/* Second word of new stack is function address */ /* Second word of new stack is function address */
((unsigned long *)align((lib_stack_bot_addr - 1), 8))[-1] = ((unsigned long *)align((stack_bot_addr - 1), 8))[-1] =
(unsigned long)func; (unsigned long)func;
/* Update the stack address */
lib_stack_bot_addr -= lib_stack_size;
/* Add child to the global task list */ /* Add child to the global task list */
child->tid = ids->tid; child->tid = ids->tid;
l4t_global_add_task(child); global_add_task(child);
/* Start the new thread */ /* Start the new thread */
if ((err = l4_thread_control(THREAD_RUN, ids)) < 0) { if ((err = l4_thread_control(THREAD_RUN, ids)) < 0) {
printf("libl4thread: l4_thread_control(THREAD_RUN) " printf("libl4thread: l4_thread_control(THREAD_RUN) "
"failed with (%d).\n", err); "failed with (%d).\n", err);
return err; goto out_err6;
} }
/* Release the global mutex. */
l4_mutex_unlock(&lib_mutex);
return 0; return 0;
/* Error handling. */
out_err6:
global_remove_task(child);
out_err5:
l4_thread_control(THREAD_DESTROY, ids);
out_err4:
delete_stack_space((void *)child->stack_addr);
out_err3:
delete_utcb_addr(child);
out_err2:
if ((flags & TC_COPY_SPACE) || (flags & TC_NEW_SPACE))
kfree(child->utcb_head);
kfree(child);
out_err1:
l4_mutex_unlock(&lib_mutex);
return err;
} }
void l4thread_kill(struct task_ids *ids) void l4_thread_exit(int retval)
{ {
struct l4t_tcb *task; struct tcb *task;
struct task_ids ids;
/* Find the task to be killed. */ /* Before doing any operation get the global mutex. */
task = l4t_find_task(ids->tid); l4_mutex_lock(&lib_mutex);
/* Find the task. */
l4_getid(&ids);
/* Cant find the thread means it wasnt added to the list. */
if (!(task = find_task(ids.tid)))
BUG();
/* Remove child from the global task list. */
global_remove_task(task);
/* Delete the stack space. */
if (delete_stack_space((void *)task->stack_addr) < 0)
BUG();
/* Delete the utcb address. */ /* Delete the utcb address. */
delete_utcb_addr(task); delete_utcb_addr(task);
// FIXME: We assume that main thread never leaves the scene
// FIXME: What happens to task->utcb_head?
kfree(task);
/* Release the global mutex. */
l4_mutex_unlock(&lib_mutex);
/* Relinquish the control. */
l4_exit(retval);
/* Should never reach here. */
BUG();
}
int l4_thread_kill(struct task_ids *ids)
{
struct tcb *task;
/* Before doing any operation get the global mutex. */
l4_mutex_lock(&lib_mutex);
/* Find the task to be killed. */
if (!(task = find_task(ids->tid))) {
l4_mutex_unlock(&lib_mutex);
return -ESRCH;
}
/* Remove child from the global task list. */ /* Remove child from the global task list. */
l4t_global_remove_task(task); global_remove_task(task);
/* Delete the stack space. */
if (delete_stack_space((void *)task->stack_addr) < 0)
BUG();
/* Delete the utcb address. */
delete_utcb_addr(task);
// FIXME: We assume that main thread never leaves the scene // FIXME: We assume that main thread never leaves the scene
// FIXME: What happens to task->utcb_head?
kfree(task); kfree(task);
/* Release the global mutex. */
l4_mutex_unlock(&lib_mutex);
/* Finally, destroy the thread. */ /* Finally, destroy the thread. */
l4_thread_control(THREAD_DESTROY, ids); l4_thread_control(THREAD_DESTROY, ids);
return 0;
} }

View File

@@ -1,7 +1,7 @@
/* /*
* UTCB management in Codezero * UTCB management in libl4thread.
* *
* Copyright © 2009 B Labs Ltd * Copyright © 2009 B Labs Ltd.
*/ */
#include <stdio.h> #include <stdio.h>
#include <addr.h> #include <addr.h>
@@ -18,7 +18,7 @@ int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end)
/* Initialise the global utcb virtual address pool */ /* Initialise the global utcb virtual address pool */
if ((err = address_pool_init(&utcb_region_pool, if ((err = address_pool_init(&utcb_region_pool,
utcb_start, utcb_end, utcb_start, utcb_end,
UTCB_SIZE) < 0)) { PAGE_SIZE) < 0)) {
printf("UTCB address pool initialisation failed.\n"); printf("UTCB address pool initialisation failed.\n");
return err; return err;
} }
@@ -26,14 +26,14 @@ int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end)
return 0; 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 */ /* Return an empty utcb slot in this descriptor */
@@ -72,7 +72,11 @@ struct utcb_desc *utcb_new_desc(void)
/* Obtain a new and unique utcb base */ /* Obtain a new and unique utcb base */
/* FIXME: Use variable size than a page */ /* 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; return d;
} }

View File

@@ -1,5 +1,5 @@
/* /*
* UTCB handling helper routines * UTCB handling helper routines.
* *
* Copyright (C) 2009 B Labs Ltd. * Copyright (C) 2009 B Labs Ltd.
*/ */
@@ -13,10 +13,13 @@
#include <utcb.h> #include <utcb.h>
/* Extern declarations */ /* 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 */ /* Function definitions */
unsigned long get_utcb_addr(struct l4t_tcb *task) unsigned long get_utcb_addr(struct tcb *task)
{ {
struct utcb_desc *udesc; struct utcb_desc *udesc;
unsigned long slot; unsigned long slot;
@@ -30,7 +33,8 @@ unsigned long get_utcb_addr(struct l4t_tcb *task)
goto found; goto found;
/* Allocate a new utcb memory region and return its base. */ /* 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); slot = utcb_new_slot(udesc);
list_insert(&udesc->list, &task->utcb_head->list); list_insert(&udesc->list, &task->utcb_head->list);
found: found:
@@ -39,7 +43,7 @@ found:
return slot; return slot;
} }
int delete_utcb_addr(struct l4t_tcb *task) int delete_utcb_addr(struct tcb *task)
{ {
struct utcb_desc *udesc; struct utcb_desc *udesc;
@@ -68,55 +72,56 @@ static int set_utcb_addr(void)
{ {
struct exregs_data exregs; struct exregs_data exregs;
struct task_ids ids; struct task_ids ids;
struct l4t_tcb *task; struct tcb *task;
struct utcb_desc *udesc; struct utcb_desc *udesc;
int err; int err;
/* Create a task. */ /* Create a task. */
if (IS_ERR(task = l4t_tcb_alloc_init(0, 0))) if (IS_ERR(task = tcb_alloc_init(0, 0)))
return -ENOMEM; return -ENOMEM;
/* Add child to the global task list. */ /* Add child to the global task list. */
list_insert_tail(&task->list, &l4t_global_tasks.list); list_insert_tail(&task->list, &global_tasks.list);
l4t_global_tasks.total++; global_tasks.total++;
udesc = utcb_new_desc(); if (!(udesc = utcb_new_desc()))
return -ENOMEM;
task->utcb_addr = utcb_new_slot(udesc); task->utcb_addr = utcb_new_slot(udesc);
list_insert(&udesc->list, &task->utcb_head->list); list_insert(&udesc->list, &task->utcb_head->list);
memset(&exregs, 0, sizeof(exregs)); memset(&exregs, 0, sizeof(exregs));
exregs_set_utcb(&exregs, (unsigned long)task->utcb_addr); exregs_set_utcb(&exregs, task->utcb_addr);
l4_getid(&ids); l4_getid(&ids);
task->tid = ids.tid;
if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) { if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) {
printf("libl4thread: l4_exchange_registers failed with " printf("libl4thread: l4_exchange_registers failed with "
"(%d).\n", err); "(%d).\n", err);
return err; return err;
} }
return 0; 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; int err;
/* Ensure that arguments are valid. */ /* Ensure that arguments are valid. */
// FIXME: Check if set_utcb_params is called if (IS_UTCB_SETUP()) {
/*if (IS_UTCB_SETUP()) {*/ printf("libl4thread: You have already called: %s.\n",
/*printf("libl4thread: You have already called: %s.\n",*/ __FUNCTION__);
/*__FUNCTION__);*/ return -EPERM;
/*return -EPERM;*/ }
/*}*/
if (!utcb_start || !utcb_end) { if (!utcb_start || !utcb_end) {
printf("libl4thread: Utcb address range cannot contain " printf("libl4thread: Utcb address range cannot contain "
"0x0 as a start and/or end address(es).\n"); "0x0 as a start and/or end address(es).\n");
return -EINVAL; return -EINVAL;
} }
/* Check if the start address is aligned on UTCB_SIZE. */ /* Check if the start address is aligned on PAGE_SIZE. */
if (utcb_start & !UTCB_SIZE) { if (utcb_start & PAGE_MASK) {
printf("libl4thread: Utcb start address must be aligned " 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; return -EINVAL;
} }
/* The range must be a valid one. */ /* The range must be a valid one. */
@@ -128,7 +133,7 @@ int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end)
/* /*
* This check guarantees two things: * This check guarantees two things:
* 1. The range must be multiple of UTCB_SIZE, at least one item. * 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) { if ((utcb_end - utcb_start) % UTCB_SIZE) {
printf("libl4thread: The given range size must be multiple " printf("libl4thread: The given range size must be multiple "
@@ -137,12 +142,19 @@ int set_utcb_params(unsigned long utcb_start, unsigned long utcb_end)
} }
/* Arguments passed the validity tests. */ /* Arguments passed the validity tests. */
/* Init utcb virtual address pool */ /* 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) if ((err = set_utcb_addr()) < 0)
return err; BUG();
/* Initialize internal variables. */
lib_utcb_range_size = utcb_end - utcb_start;
return 0; return 0;
} }