Integrated libl4thread with libl4. Added device number to device caps.

A 16-bit device number or id further distinguishes a device on the
system in addition to the device type. This is meant to be used for
the very first identification of the device for further probing. Any
further info is available by userspace mapping and probing.
This commit is contained in:
Bahadir Balban
2009-11-22 21:34:18 +02:00
parent 26d469fccd
commit 877b2cedc7
29 changed files with 84 additions and 149 deletions

View File

@@ -30,14 +30,19 @@ Import('arch')
config = configuration_retrieve()
LIBMEM_RELDIR = 'conts/libmem'
LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR)
env = Environment(CC = config.user_toolchain + 'gcc',
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding'],
CCFLAGS = ['-g', '-std=gnu99', '-nostdlib', '-ffreestanding'],
LINKFLAGS = ['-nostdlib'],
ASFLAGS = ['-D__ASSEMBLY__'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc',
CPPPATH = ['include', 'include/l4lib/arch', join(PROJROOT, 'include') ])
env.Append(CPPPATH = [LIBMEM_DIR])
def create_symlinks(arch):
print os.getcwd()
prefix = 'conts/libl4/include/l4lib'

View File

@@ -17,12 +17,12 @@ config = configuration_retrieve()
arch = config.arch
env = Environment(CC = config.user_toolchain + 'gcc',
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding'],
CCFLAGS = ['-std=gnu99', '-g', '-nostdlib', '-ffreestanding'],
LINKFLAGS = ['-nostdlib'],
ASFLAGS = ['-D__ASSEMBLY__'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc',
CPPPATH = ['#include', '#include/l4lib/arch', join(PROJROOT,'include') ])
CPPPATH = ['#include', '#include/l4lib/arch', join(PROJROOT,'include')])
# TODO: There are errors in this code that -Werror gives problems with.

View File

@@ -0,0 +1,27 @@
/*
* Address allocation pool.
*
* Copyright (C) 2007 Bahadir Balban
*/
#ifndef __ADDR_H__
#define __ADDR_H__
#include <l4lib/idpool.h>
/* 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 nitems, int size);
int address_del(struct address_pool *, void *addr, int nitems, int size);
#endif /* __ADDR_H__ */

View File

@@ -0,0 +1,44 @@
#ifndef __BIT_H__
#define __BIT_H__
#include <l4lib/types.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__ */

View File

@@ -0,0 +1,31 @@
#ifndef __IDPOOL_H__
#define __IDPOOL_H__
#include <l4lib/bit.h>
#include <string.h>
#include <l4/macros.h>
#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__ */

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

@@ -0,0 +1,43 @@
/*
* Thread control block.
*
* Copyright (C) 2009 B Labs Ltd.
*/
#ifndef __LIB_TCB_H__
#define __LIB_TCB_H__
#include <l4/lib/list.h>
/* 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 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;
};
/* All the threads handled by the thread lib are kept in this list. */
struct global_list {
int total;
struct link list;
};
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__ */

View File

@@ -11,4 +11,22 @@ struct l4_thread_struct {
unsigned long stack_start; /* Thread start of stack */
};
/* -- Bora start -- */
/* 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);
int l4_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end);
int l4_thread_create(struct task_ids *ids, unsigned int flags,
int (*func)(void *), void *arg);
void l4_thread_exit(int retval);
/* -- Bora start -- */
#endif /* __L4_THREAD_H__ */

View File

@@ -0,0 +1,25 @@
/*
* UTCB handling common helper routines.
*
* Copyright (C) 2009 B Labs Ltd.
*/
#ifndef __UTCB_COMMON_H__
#define __UTCB_COMMON_H__
#include <l4/lib/list.h>
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__ */

View File

@@ -9,4 +9,14 @@
int utcb_init(void);
/* Bora start */
#include <l4lib/tcb.h>
/* 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);
/* Bora end */
#endif /* __UTCB_H__ */

57
conts/libl4/src/addr.c Normal file
View File

@@ -0,0 +1,57 @@
/*
* This module allocates an unused address range from
* a given memory region defined as the pool range.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4lib/addr.h>
#include <stdio.h>
/*
* 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 nitems, int size)
{
unsigned int idx;
if ((int)(idx = ids_new_contiguous(pool->idpool, nitems)) < 0)
return 0;
return (void *)(idx * size) + pool->start;
}
int address_del(struct address_pool *pool, void *addr, int nitems, int size)
{
unsigned long idx = (addr - (void *)pool->start) / size;
if (ids_del_contiguous(pool->idpool, idx, nitems) < 0) {
printf("%s: Invalid address range returned to "
"virtual address pool.\n", __FUNCTION__);
return -1;
}
return 0;
}

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)

109
conts/libl4/src/bit.c Normal file
View File

@@ -0,0 +1,109 @@
/*
* Bit manipulation functions.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4lib/bit.h>
#include <stdio.h>
#include <l4/macros.h>
#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. */
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;
}

87
conts/libl4/src/idpool.c Normal file
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 <l4lib/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;
}

97
conts/libl4/src/stack.c Normal file
View File

@@ -0,0 +1,97 @@
/*
* Stack management in libl4thread.
*
* Copyright © 2009 B Labs Ltd.
*/
#include <stdio.h>
#include <l4/api/errno.h>
#include <l4lib/addr.h>
#include <l4lib/mutex.h>
#include <l4lib/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;
}

65
conts/libl4/src/tcb.c Normal file
View File

@@ -0,0 +1,65 @@
/*
* Thread management in libl4thread.
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <stdio.h>
#include <malloc/malloc.h>
#include <l4/api/errno.h>
#include <l4/api/thread.h>
#include <l4lib/tcb.h>
#include <l4/macros.h>
/* Global task list. */
struct global_list global_tasks = {
.list = { &global_tasks.list, &global_tasks.list },
.total = 0,
};
/* Function definitions */
void global_add_task(struct tcb *task)
{
BUG_ON(!list_empty(&task->list));
list_insert_tail(&task->list, &global_tasks.list);
global_tasks.total++;
}
void global_remove_task(struct tcb *task)
{
BUG_ON(list_empty(&task->list));
list_remove_init(&task->list);
BUG_ON(--global_tasks.total < 0);
}
struct tcb *find_task(int tid)
{
struct tcb *t;
list_foreach_struct(t, &global_tasks.list, list)
if (t->tid == tid)
return t;
return 0;
}
struct tcb *tcb_alloc_init(struct tcb *parent, unsigned int flags)
{
struct tcb *task;
if (!(task = kzalloc(sizeof(struct tcb))))
return PTR_ERR(-ENOMEM);
link_init(&task->list);
if (flags & TC_SHARE_SPACE)
task->utcb_head = parent->utcb_head;
else {
/* 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);
}
return task;
}

210
conts/libl4/src/thread.c Normal file
View File

@@ -0,0 +1,210 @@
/*
* Thread creation userspace helpers
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <stdio.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/arch/syslib.h>
#include <l4lib/exregs.h>
#include <l4lib/mutex.h>
#include <l4/api/thread.h>
#include <l4/api/errno.h>
#include <malloc/malloc.h>
#include <l4lib/utcb.h>
#include <l4lib/stack.h>
/* 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,
int (*func)(void *), void *arg)
{
struct exregs_data exregs;
unsigned long utcb_addr;
struct tcb *parent, *child;
unsigned long stack_top_addr, stack_bot_addr;
int err = 0;
/* 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.\n");
return -EPERM;
}
/* 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 = find_task(ids->tid))) {
err = -ESRCH;
goto out_err1;
}
/* Allocate tcb for the child. */
if (!(child = tcb_alloc_init(parent, flags))) {
// FIXME: What happens to utcb_head
printf("libl4thread: No heap space left.\n");
err = -ENOMEM;
goto out_err1;
}
/* Get a utcb addr. */
if (!(utcb_addr = get_utcb_addr(child))) {
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);
goto out_err4;
}
/* Setup new thread pc, sp, utcb */
memset(&exregs, 0, sizeof(exregs));
exregs_set_stack(&exregs, align((stack_bot_addr - 1), 8));
exregs_set_pc(&exregs, (unsigned long)setup_new_thread);
exregs_set_utcb(&exregs, (unsigned long)utcb_addr);
if ((err = l4_exchange_registers(&exregs, ids->tid)) < 0) {
printf("libl4thread: l4_exchange_registers failed with "
"(%d).\n", err);
goto out_err5;
}
/* First word of new stack is arg */
((unsigned long *)align((stack_bot_addr - 1), 8))[0] =
(unsigned long)arg;
/* Second word of new stack is function address */
((unsigned long *)align((stack_bot_addr - 1), 8))[-1] =
(unsigned long)func;
/* Add child to the global task list */
child->tid = ids->tid;
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);
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(int retval)
{
struct tcb *task;
struct task_ids ids;
/* Before doing any operation get the global mutex. */
l4_mutex_lock(&lib_mutex);
/* Find the task. */
l4_getid(&ids);
/* Cant find the thread means it wasnt added to the list. */
if (!(task = find_task(ids.tid)))
BUG();
/* Remove child from the global task list. */
global_remove_task(task);
/* Delete the stack space. */
if (delete_stack_space((void *)task->stack_addr) < 0)
BUG();
/* Delete the utcb address. */
delete_utcb_addr(task);
// FIXME: We assume that main thread never leaves the scene
// FIXME: What happens to task->utcb_head?
kfree(task);
/* Release the global mutex. */
l4_mutex_unlock(&lib_mutex);
/* Relinquish the control. */
l4_exit(retval);
/* Should never reach here. */
BUG();
}
int l4_thread_kill(struct task_ids *ids)
{
struct tcb *task;
/* Before doing any operation get the global mutex. */
l4_mutex_lock(&lib_mutex);
/* Find the task to be killed. */
if (!(task = find_task(ids->tid))) {
l4_mutex_unlock(&lib_mutex);
return -ESRCH;
}
/* Remove child from the global task list. */
global_remove_task(task);
/* Delete the stack space. */
if (delete_stack_space((void *)task->stack_addr) < 0)
BUG();
/* Delete the utcb address. */
delete_utcb_addr(task);
// FIXME: We assume that main thread never leaves the scene
// FIXME: What happens to task->utcb_head?
kfree(task);
/* Release the global mutex. */
l4_mutex_unlock(&lib_mutex);
/* Finally, destroy the thread. */
l4_thread_control(THREAD_DESTROY, ids);
return 0;
}

View File

@@ -0,0 +1,93 @@
/*
* UTCB management in libl4thread.
*
* Copyright © 2009 B Labs Ltd.
*/
#include <stdio.h>
#include <l4lib/addr.h>
#include <l4lib/utcb-common.h>
#include <malloc/malloc.h>
/* 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,
PAGE_SIZE) < 0)) {
printf("UTCB address pool initialisation failed.\n");
return err;
}
return 0;
}
static inline void *utcb_new_address(int nitems)
{
return address_new(&utcb_region_pool, nitems, PAGE_SIZE);
}
static inline int utcb_delete_address(void *utcb_address, int nitems)
{
return address_del(&utcb_region_pool, utcb_address, nitems, PAGE_SIZE);
}
/* 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 */
if (!(d->utcb_base = (unsigned long)utcb_new_address(1))) {
kfree(d->slots);
kfree(d);
return 0;
}
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;
}

160
conts/libl4/src/utcb.c Normal file
View File

@@ -0,0 +1,160 @@
/*
* UTCB handling helper routines.
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <stdio.h>
#include <malloc/malloc.h>
#include <l4/api/errno.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/exregs.h>
#include <l4lib/idpool.h>
#include <l4lib/utcb-common.h>
#include <l4lib/utcb.h>
/* Extern declarations */
extern struct global_list global_tasks;
/* Global variables */
unsigned long lib_utcb_range_size;
/* Function definitions */
unsigned long get_utcb_addr(struct 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. */
if (!(udesc = utcb_new_desc()))
return 0;
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 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 tcb *task;
struct utcb_desc *udesc;
int err;
/* Create a task. */
if (IS_ERR(task = tcb_alloc_init(0, 0)))
return -ENOMEM;
/* Add child to the global task list. */
list_insert_tail(&task->list, &global_tasks.list);
global_tasks.total++;
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, 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);
return err;
}
return 0;
}
int l4_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;
}
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 PAGE_SIZE. */
if (utcb_start & PAGE_MASK) {
printf("libl4thread: Utcb start address must be aligned "
"on PAGE_SIZE(0x%x).\n", PAGE_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. */
if (utcb_pool_init(utcb_start, utcb_end) < 0)
BUG();
/*
* The very first thread's utcb address is assigned.
* It should not return an error value.
*/
if ((err = set_utcb_addr()) < 0)
BUG();
/* Initialize internal variables. */
lib_utcb_range_size = utcb_end - utcb_start;
return 0;
}