mirror of
https://github.com/drasko/codezero.git
synced 2026-03-11 06:43:16 +01:00
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:
57
conts/libl4/src/addr.c
Normal file
57
conts/libl4/src/addr.c
Normal 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;
|
||||
}
|
||||
|
||||
12
conts/libl4/src/arm/new_thread.S
Normal file
12
conts/libl4/src/arm/new_thread.S
Normal 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
109
conts/libl4/src/bit.c
Normal 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
87
conts/libl4/src/idpool.c
Normal 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
97
conts/libl4/src/stack.c
Normal 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
65
conts/libl4/src/tcb.c
Normal 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
210
conts/libl4/src/thread.c
Normal 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;
|
||||
}
|
||||
93
conts/libl4/src/utcb-common.c
Normal file
93
conts/libl4/src/utcb-common.c
Normal 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
160
conts/libl4/src/utcb.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user