mirror of
https://github.com/drasko/codezero.git
synced 2026-10-26 11:47:27 +01:00
1. Old pending files cleaned from public repo. 2. Thread_create routines removed from timer_service and kmi_service. 3. Sconstruct of libdev updated.
This commit is contained in:
@@ -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 <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,
|
||||
unsigned int size)
|
||||
{
|
||||
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 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;
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Generic to arch-specific interface for
|
||||
* exchange_registers()
|
||||
*
|
||||
* Copyright (C) 2008 Bahadir Balban
|
||||
*/
|
||||
#include <l4/macros.h>
|
||||
#include <l4lib/exregs.h>
|
||||
#include <l4lib/arch/syslib.h>
|
||||
#include INC_GLUE(message.h)
|
||||
|
||||
void exregs_print_registers(void)
|
||||
{
|
||||
struct exregs_data exregs;
|
||||
|
||||
/* Read registers */
|
||||
memset(&exregs, 0, sizeof(exregs));
|
||||
exregs.valid_vect = ~0; /* Set all flags */
|
||||
exregs.flags |= EXREGS_READ;
|
||||
exregs.flags |= EXREGS_SET_UTCB;
|
||||
exregs.flags |= EXREGS_SET_PAGER;
|
||||
BUG_ON(l4_exchange_registers(&exregs, self_tid()) < 0);
|
||||
|
||||
/* Print out registers */
|
||||
printf("Task (%x) register state upon fault:\n", self_tid());
|
||||
printf("R0: 0x%x\n", exregs.context.r0);
|
||||
printf("R1: 0x%x\n", exregs.context.r1);
|
||||
printf("R2: 0x%x\n", exregs.context.r2);
|
||||
printf("R3: 0x%x\n", exregs.context.r3);
|
||||
printf("R4: 0x%x\n", exregs.context.r4);
|
||||
printf("R5: 0x%x\n", exregs.context.r5);
|
||||
printf("R6: 0x%x\n", exregs.context.r6);
|
||||
printf("R7: 0x%x\n", exregs.context.r7);
|
||||
printf("R8: 0x%x\n", exregs.context.r8);
|
||||
printf("R9: 0x%x\n", exregs.context.r9);
|
||||
printf("R10: 0x%x\n", exregs.context.r10);
|
||||
printf("R11: 0x%x\n", exregs.context.r11);
|
||||
printf("R12: 0x%x\n", exregs.context.r12);
|
||||
printf("R13: 0x%x\n", exregs.context.sp);
|
||||
printf("R14: 0x%x\n", exregs.context.lr);
|
||||
printf("R15: 0x%x\n", exregs.context.pc);
|
||||
printf("Pager: 0x%x\n", exregs.pagerid);
|
||||
printf("Utcb @ 0x%lx\n", exregs.utcb_address);
|
||||
}
|
||||
|
||||
void exregs_set_mr(struct exregs_data *s, int offset, unsigned long val)
|
||||
{
|
||||
/* Get MR0 */
|
||||
u32 *mr = &s->context.MR0_REGISTER;
|
||||
|
||||
/* Sanity check */
|
||||
BUG_ON(offset > MR_TOTAL || offset < 0);
|
||||
|
||||
/* Set MR */
|
||||
mr[offset] = val;
|
||||
|
||||
/* Set valid bit for mr register */
|
||||
s->valid_vect |= FIELD_TO_BIT(exregs_context_t, MR0_REGISTER) << offset;
|
||||
}
|
||||
|
||||
void exregs_set_pager(struct exregs_data *s, l4id_t pagerid)
|
||||
{
|
||||
s->pagerid = pagerid;
|
||||
s->flags |= EXREGS_SET_PAGER;
|
||||
}
|
||||
|
||||
void exregs_set_utcb(struct exregs_data *s, unsigned long virt)
|
||||
{
|
||||
s->utcb_address = virt;
|
||||
s->flags |= EXREGS_SET_UTCB;
|
||||
}
|
||||
|
||||
void exregs_set_stack(struct exregs_data *s, unsigned long sp)
|
||||
{
|
||||
s->context.sp = sp;
|
||||
s->valid_vect |= FIELD_TO_BIT(exregs_context_t, sp);
|
||||
}
|
||||
|
||||
void exregs_set_pc(struct exregs_data *s, unsigned long pc)
|
||||
{
|
||||
s->context.pc = pc;
|
||||
s->valid_vect |= FIELD_TO_BIT(exregs_context_t, pc);
|
||||
}
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Bahadir Balban
|
||||
*/
|
||||
|
||||
#include <l4lib/arch/asm.h>
|
||||
#include <l4lib/mutex.h>
|
||||
|
||||
/*
|
||||
* NOTES:
|
||||
*
|
||||
* Recap on swp:
|
||||
*
|
||||
* swp rx, ry, [rz]
|
||||
*
|
||||
* In one instruction:
|
||||
*
|
||||
* 1) Stores the value in ry into location pointed by rz.
|
||||
* 2) Loads the value in the location of rz into rx.
|
||||
* By doing so, in one instruction one can attempt to lock
|
||||
* a word, and discover whether it was already locked.
|
||||
*
|
||||
* Why use tid of thread to lock mutex instead of
|
||||
* a single lock value?
|
||||
*
|
||||
* Because in one atomic instruction, not only the locking attempt
|
||||
* should be able to indicate whether it is locked, but also
|
||||
* the contentions. A unified lock value would not be sufficient.
|
||||
* The only way to indicate a contended lock is to store the
|
||||
* unique TID of the locker.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Any non-negative value that is a potential TID
|
||||
* (including 0) means mutex is locked.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @r0 = address of mutex word
|
||||
* @r1 = unique tid of current thread
|
||||
*/
|
||||
BEGIN_PROC(__l4_mutex_lock)
|
||||
swp r2, r1, [r0]
|
||||
cmp r2, #L4_MUTEX_UNLOCKED @ Was the lock available?
|
||||
movne r0, #L4_MUTEX_CONTENDED @ Indicate failure
|
||||
moveq r0, #L4_MUTEX_SUCCESS @ Indicate success
|
||||
mov pc, lr
|
||||
END_PROC(__l4_mutex_lock)
|
||||
|
||||
/*
|
||||
* @r0 = address of mutex word
|
||||
* @r1 = unique tid of current thread
|
||||
*/
|
||||
BEGIN_PROC(__l4_mutex_unlock)
|
||||
mov r3, #L4_MUTEX_UNLOCKED
|
||||
swp r2, r3, [r0]
|
||||
cmp r2, r1 @ Check lock had original tid value
|
||||
movne r0, #L4_MUTEX_CONTENDED @ Indicate contention
|
||||
moveq r0, #L4_MUTEX_SUCCESS @ Indicate no contention
|
||||
cmp r2, #L4_MUTEX_UNLOCKED @ Or - was it already unlocked?
|
||||
1:
|
||||
beq 1b @ If so busy-spin to indicate bug.
|
||||
mov pc, lr
|
||||
END_PROC(__l4_mutex_unlock)
|
||||
|
||||
/*
|
||||
* r0 = byte address to read from.
|
||||
*/
|
||||
BEGIN_PROC(l4_atomic_dest_readb)
|
||||
mov r1, r0 @ Move byte address to r1
|
||||
mov r2, #0 @ Move 0 to r2
|
||||
swpb r0, r2, [r1] @ Write 0 to byte location, while reading its value to r0
|
||||
mov pc, lr @ Return byte location value
|
||||
END_PROC(l4_atomic_dest_readb)
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#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)
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
/*
|
||||
* Userspace system call interface.
|
||||
*
|
||||
* Copyright (C) 2007 - 2009 Bahadir Balban
|
||||
*/
|
||||
#include <l4lib/arch/asm.h>
|
||||
#include <l4lib/arch/utcb.h>
|
||||
#include <l4/generic/space.h>
|
||||
#include <l4/macros.h>
|
||||
#include INC_GLUE(message.h)
|
||||
|
||||
/* Old macro */
|
||||
#if 0
|
||||
.macro utcb_address rx
|
||||
ldr \rx, =utcb
|
||||
.endm
|
||||
#endif
|
||||
|
||||
/* New macro does double dereference */
|
||||
.macro utcb_address rx
|
||||
ldr \rx, =kip_utcb_ref @ First get pointer to utcb pointer in KIP
|
||||
ldr \rx, [\rx] @ Get pointer to UTCB address from UTCB pointer in KIP
|
||||
ldr \rx, [\rx] @ Get the utcb address
|
||||
.endm
|
||||
|
||||
BEGIN_PROC(l4_thread_switch)
|
||||
ldr r12, =__l4_thread_switch
|
||||
ldr pc, [r12] @ Jump into the SWI. Kernel returns to LR_USR, which is the caller.
|
||||
END_PROC(l4_thread_switch)
|
||||
|
||||
/*
|
||||
* The syscall returns process ids. This function saves the returned values in the
|
||||
* arguments passed by reference. @r0 = struct task_ids *
|
||||
*/
|
||||
BEGIN_PROC(l4_getid)
|
||||
ldr r12, =__l4_getid @ See l4_kdata_read for why its so simple.
|
||||
ldr pc, [r12] @ Return.
|
||||
END_PROC(l4_getid)
|
||||
|
||||
/*
|
||||
* For clone() we need special assembler handling
|
||||
* Same signature as ipc(): @r0 = to, @r1 = from @r2 = flags
|
||||
*
|
||||
* NOTE: Note that this breaks l4 system call interface,
|
||||
* this should be moved elsewhere and modified using existing l4 mechanisms.
|
||||
*/
|
||||
BEGIN_PROC(arch_clone)
|
||||
stmfd sp!, {r4-r8,lr} @ Save context.
|
||||
utcb_address r12 @ Get utcb address.
|
||||
ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5
|
||||
|
||||
ldr r12, =__l4_ipc
|
||||
mov lr, pc
|
||||
ldr pc, [r12] @ Perform the ipc()
|
||||
|
||||
/*
|
||||
* At this moment:
|
||||
* - MR_RETURN tells us whether we are parent or child (or have failed).
|
||||
* - Child has new SP set, with |func_ptr|arg1|{End of stack}SP<-| on stack.
|
||||
* - Child needs exit logic when its function is finished.
|
||||
*/
|
||||
cmp r0, #0 @ Check ipc success
|
||||
blt ipc_failed
|
||||
cmp MR_RETURN_REGISTER, #0 @ Check ipc return register MR_RETURN.
|
||||
blt clone_failed @ Ipc was ok but clone() failed.
|
||||
bgt parent_return @ It has child pid, goto parent return.
|
||||
child:
|
||||
ldr r0, [sp, #-4]! @ Load child's first argument.
|
||||
mov lr, pc @ Save return address
|
||||
ldr pc, [sp, #-4]! @ Load function pointer from stack
|
||||
child_exit:
|
||||
b child_exit @ We infinitely loop for now.
|
||||
|
||||
@ Return with normal ipc return sequence
|
||||
parent_return:
|
||||
clone_failed:
|
||||
ipc_failed:
|
||||
utcb_address r12 @ Get utcb
|
||||
stmia r12, {r3-r8} @ Store mrs.
|
||||
ldmfd sp!, {r4-r8,pc} @ Return restoring pc and context.
|
||||
END_PROC(arch_clone)
|
||||
|
||||
/*
|
||||
* Inter-process communication. Loads message registers as arguments before the call,
|
||||
* and stores them as results after the call. @r0 = to, @r1 = from.
|
||||
*/
|
||||
BEGIN_PROC(l4_ipc)
|
||||
stmfd sp!, {r4-r8,lr} @ Save context.
|
||||
utcb_address r12 @ Get utcb address.
|
||||
ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5
|
||||
ldr r12, =__l4_ipc
|
||||
mov lr, pc
|
||||
ldr pc, [r12]
|
||||
utcb_address r12 @ Get utcb address.
|
||||
stmia r12, {r3-r8} @ Store 6 Message registers to utcb. MR0-MR5
|
||||
ldmfd sp!, {r4-r8,pc} @ Return restoring pc, and context.
|
||||
END_PROC(l4_ipc)
|
||||
|
||||
/*
|
||||
* System call that maps an area of memory into the given address space.
|
||||
* @r0 = physical address, @r1 = virtual address, @r2 = map size in pages,
|
||||
* @r3 = map flags, @r4 = The tgid of the address space to map.
|
||||
*/
|
||||
BEGIN_PROC(l4_map)
|
||||
stmfd sp!, {r4, lr}
|
||||
ldr r4, [sp, #8] @ FIXME: Is this right?
|
||||
ldr r12, =__l4_map
|
||||
mov lr, pc @ We must return here to restore r4.
|
||||
ldr pc, [r12]
|
||||
ldmfd sp!, {r4, pc}
|
||||
END_PROC(l4_map)
|
||||
|
||||
/*
|
||||
* Reads/manipulates capabilities of a thread, particularly a pager.
|
||||
* @r0 = request type, @r1 = request flags, @r2 = Capability buffer pointer
|
||||
*/
|
||||
BEGIN_PROC(l4_capability_control)
|
||||
stmfd sp!, {lr}
|
||||
ldr r12, =__l4_capability_control
|
||||
mov lr, pc
|
||||
ldr pc, [r12]
|
||||
ldmfd sp!, {pc} @ Restore original lr and return.
|
||||
END_PROC(l4_capability_control)
|
||||
|
||||
/*
|
||||
* System call that unmaps an area of memory into the given address space.
|
||||
* @r0 = virtual, @r1 = pages, @r2 = tid of address space to unmap
|
||||
*/
|
||||
BEGIN_PROC(l4_unmap)
|
||||
stmfd sp!, {lr}
|
||||
ldr r12, =__l4_unmap
|
||||
mov lr, pc
|
||||
ldr pc, [r12]
|
||||
ldmfd sp!, {pc} @ Restore original lr and return.
|
||||
END_PROC(l4_unmap)
|
||||
|
||||
/*
|
||||
* System call that controls containers and their parameters.
|
||||
* @r0 = request type, @r1 = request flags, @r2 = io buffer ptr
|
||||
*/
|
||||
BEGIN_PROC(l4_container_control)
|
||||
stmfd sp!, {lr}
|
||||
ldr r12, =__l4_container_control
|
||||
mov lr, pc
|
||||
ldr pc, [r12]
|
||||
ldmfd sp!, {pc} @ Restore original lr and return.
|
||||
END_PROC(l4_container_control)
|
||||
|
||||
/*
|
||||
* System call that gets or sets the time info structure.
|
||||
* @r0 = ptr to time structure @r1 = set or get. set = 1, get = 0.
|
||||
*/
|
||||
BEGIN_PROC(l4_time)
|
||||
stmfd sp!, {lr}
|
||||
ldr r12, =__l4_time
|
||||
mov lr, pc
|
||||
ldr pc, [r12]
|
||||
ldmfd sp!, {pc} @ Restore original lr and return.
|
||||
END_PROC(l4_time)
|
||||
|
||||
/*
|
||||
* System call that controls thread creation, destruction and modification.
|
||||
* @r0 = thread action, @r1 = &ids, @r2 = utcb address
|
||||
*/
|
||||
BEGIN_PROC(l4_thread_control)
|
||||
stmfd sp!, {lr}
|
||||
ldr r12, =__l4_thread_control
|
||||
mov lr, pc
|
||||
ldr pc, [r12]
|
||||
ldmfd sp!, {pc} @ Restore original lr and return.
|
||||
END_PROC(l4_thread_control)
|
||||
|
||||
/*
|
||||
* System call that modifies ipc blocked sender lists of receivers.
|
||||
* @r0 = Action (e.g. block/unblock), @r1 = sender id, @r2 = sender tag
|
||||
*/
|
||||
BEGIN_PROC(l4_ipc_control)
|
||||
stmfd sp!, {lr}
|
||||
ldr r12, =__l4_ipc_control
|
||||
mov lr, pc
|
||||
ldr pc, [r12]
|
||||
ldmfd sp!, {pc} @ Restore original lr and return.
|
||||
END_PROC(l4_ipc_control)
|
||||
|
||||
/*
|
||||
* Manipulates address spaces, e.g. sets up shared memory areas between threads
|
||||
* @r0 = operation code, @r1 = operation flags, @r2 = An id (irqnum, or capid)
|
||||
*/
|
||||
BEGIN_PROC(l4_irq_control)
|
||||
stmfd sp!, {lr}
|
||||
ldr r12, =__l4_irq_control
|
||||
mov lr, pc
|
||||
ldr pc, [r12]
|
||||
ldmfd sp!, {pc} @ Restore original lr and return.
|
||||
END_PROC(l4_irq_control)
|
||||
|
||||
/*
|
||||
* Locks/unlocks a userspace mutex.
|
||||
* @r0 = mutex virtual address, @r1 = mutex operation code
|
||||
*/
|
||||
BEGIN_PROC(l4_mutex_control)
|
||||
stmfd sp!, {lr}
|
||||
ldr r12, =__l4_mutex_control
|
||||
mov lr, pc
|
||||
ldr pc, [r12]
|
||||
ldmfd sp!, {pc} @ Restore original lr and return.
|
||||
END_PROC(l4_mutex_control)
|
||||
|
||||
/*
|
||||
* Sets registers of a thread and its pager.
|
||||
* @r0 = ptr to exregs_data structure, @r1 = tid of thread.
|
||||
*/
|
||||
BEGIN_PROC(l4_exchange_registers)
|
||||
stmfd sp!, {lr}
|
||||
ldr r12, =__l4_exchange_registers
|
||||
mov lr, pc
|
||||
ldr pc, [r12]
|
||||
ldmfd sp!, {pc} @ Restore original lr and return.
|
||||
END_PROC(l4_exchange_registers)
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
|
||||
|
||||
/* Capability printing generic routines */
|
||||
|
||||
#include <l4lib/capability/cap_print.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void cap_dev_print(struct capability *cap)
|
||||
{
|
||||
switch (cap_devtype(cap)) {
|
||||
case CAP_DEVTYPE_UART:
|
||||
printf("Device type:\t\t\t%s%d\n", "UART", cap_devnum(cap));
|
||||
break;
|
||||
case CAP_DEVTYPE_TIMER:
|
||||
printf("Device type:\t\t\t%s%d\n", "Timer", cap_devnum(cap));
|
||||
break;
|
||||
case CAP_DEVTYPE_CLCD:
|
||||
printf("Device type:\t\t\t%s%d\n", "CLCD", cap_devnum(cap));
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
printf("Device Irq:\t\t%d\n", cap->irq);
|
||||
}
|
||||
|
||||
void cap_print(struct capability *cap)
|
||||
{
|
||||
printf("Capability id:\t\t\t%d\n", cap->capid);
|
||||
printf("Capability resource id:\t\t%d\n", cap->resid);
|
||||
printf("Capability owner id:\t\t%d\n",cap->owner);
|
||||
|
||||
switch (cap_type(cap)) {
|
||||
case CAP_TYPE_TCTRL:
|
||||
printf("Capability type:\t\t%s\n", "Thread Control");
|
||||
break;
|
||||
case CAP_TYPE_EXREGS:
|
||||
printf("Capability type:\t\t%s\n", "Exchange Registers");
|
||||
break;
|
||||
case CAP_TYPE_MAP_PHYSMEM:
|
||||
if (!cap_is_devmem(cap)) {
|
||||
printf("Capability type:\t\t%s\n", "Map/Physmem");
|
||||
} else {
|
||||
printf("Capability type:\t\t%s\n", "Map/Physmem/Device");
|
||||
cap_dev_print(cap);
|
||||
}
|
||||
break;
|
||||
case CAP_TYPE_MAP_VIRTMEM:
|
||||
printf("Capability type:\t\t%s\n", "Map/Virtmem");
|
||||
break;
|
||||
case CAP_TYPE_IPC:
|
||||
printf("Capability type:\t\t%s\n", "Ipc");
|
||||
break;
|
||||
case CAP_TYPE_UMUTEX:
|
||||
printf("Capability type:\t\t%s\n", "Mutex");
|
||||
break;
|
||||
case CAP_TYPE_IRQCTRL:
|
||||
printf("Capability type:\t\t%s\n", "IRQ Control");
|
||||
break;
|
||||
case CAP_TYPE_QUANTITY:
|
||||
printf("Capability type:\t\t%s\n", "Quantitative");
|
||||
break;
|
||||
case CAP_TYPE_CAP:
|
||||
printf("Capability type:\t\t%s\n", "Capability Control");
|
||||
break;
|
||||
default:
|
||||
printf("Capability type:\t\t%s, cap_type=0x%x\n",
|
||||
"Unknown", cap_type(cap));
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cap_rtype(cap)) {
|
||||
case CAP_RTYPE_THREAD:
|
||||
printf("Capability resource type:\t%s\n", "Thread");
|
||||
break;
|
||||
case CAP_RTYPE_SPACE:
|
||||
printf("Capability resource type:\t%s\n", "Space");
|
||||
break;
|
||||
case CAP_RTYPE_CONTAINER:
|
||||
printf("Capability resource type:\t%s\n", "Container");
|
||||
break;
|
||||
case CAP_RTYPE_THREADPOOL:
|
||||
printf("Capability resource type:\t%s\n", "Thread Pool");
|
||||
break;
|
||||
case CAP_RTYPE_SPACEPOOL:
|
||||
printf("Capability resource type:\t%s\n", "Space Pool");
|
||||
break;
|
||||
case CAP_RTYPE_MUTEXPOOL:
|
||||
printf("Capability resource type:\t%s\n", "Mutex Pool");
|
||||
break;
|
||||
case CAP_RTYPE_MAPPOOL:
|
||||
printf("Capability resource type:\t%s\n", "Map Pool (PMDS)");
|
||||
break;
|
||||
case CAP_RTYPE_CPUPOOL:
|
||||
printf("Capability resource type:\t%s\n", "Cpu Pool");
|
||||
break;
|
||||
case CAP_RTYPE_CAPPOOL:
|
||||
printf("Capability resource type:\t%s\n", "Capability Pool");
|
||||
break;
|
||||
default:
|
||||
printf("Capability resource type:\t%s, id=0x%x\n", "Unknown",
|
||||
cap_rtype(cap));
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void cap_array_print(int total_caps, struct capability *caparray)
|
||||
{
|
||||
printf("Capabilities\n"
|
||||
"~~~~~~~~~~~~\n");
|
||||
|
||||
for (int i = 0; i < total_caps; i++)
|
||||
cap_print(&caparray[i]);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* 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/thread/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;
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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/thread/tcb.h>
|
||||
#include <l4/macros.h>
|
||||
|
||||
/* Global task list. */
|
||||
struct l4lib_global_list global_tasks = {
|
||||
.list = { &global_tasks.list, &global_tasks.list },
|
||||
.total = 0,
|
||||
};
|
||||
|
||||
/* Function definitions */
|
||||
void l4lib_global_add_task(struct l4lib_tcb *task)
|
||||
{
|
||||
BUG_ON(!list_empty(&task->list));
|
||||
list_insert_tail(&task->list, &global_tasks.list);
|
||||
global_tasks.total++;
|
||||
}
|
||||
|
||||
void l4lib_global_remove_task(struct l4lib_tcb *task)
|
||||
{
|
||||
BUG_ON(list_empty(&task->list));
|
||||
list_remove_init(&task->list);
|
||||
BUG_ON(--global_tasks.total < 0);
|
||||
}
|
||||
|
||||
struct l4lib_tcb * l4lib_find_task(int tid)
|
||||
{
|
||||
struct l4lib_tcb *t;
|
||||
|
||||
list_foreach_struct(t, &global_tasks.list, list)
|
||||
if (t->tid == tid)
|
||||
return t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct l4lib_tcb *l4_tcb_alloc_init(struct l4lib_tcb *parent, unsigned int flags)
|
||||
{
|
||||
struct l4lib_tcb *task;
|
||||
|
||||
if (!(task = kzalloc(sizeof(struct l4lib_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 l4lib_utcb_head)))) {
|
||||
kfree(task);
|
||||
return PTR_ERR(-ENOMEM);
|
||||
}
|
||||
link_init(&task->utcb_head->list);
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Thread creation userspace helpers
|
||||
*
|
||||
* Copyright (C) 2009 B Labs Ltd.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <malloc/malloc.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 <l4lib/thread/utcb-common.h>
|
||||
#include <l4lib/thread/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 l4lib_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 l4lib_tcb belonging to it. */
|
||||
l4_getid(ids);
|
||||
if (!(parent = l4lib_find_task(ids->tid))) {
|
||||
err = -ESRCH;
|
||||
goto out_err1;
|
||||
}
|
||||
|
||||
/* Allocate l4lib_tcb for the child. */
|
||||
if (!(child = l4_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;
|
||||
l4lib_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:
|
||||
l4lib_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 l4lib_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 = l4lib_find_task(ids.tid)))
|
||||
BUG();
|
||||
|
||||
/* Remove child from the global task list. */
|
||||
l4lib_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 l4lib_tcb *task;
|
||||
|
||||
/* Before doing any operation get the global mutex. */
|
||||
l4_mutex_lock(&lib_mutex);
|
||||
|
||||
/* Find the task to be killed. */
|
||||
if (!(task = l4lib_find_task(ids->tid))) {
|
||||
l4_mutex_unlock(&lib_mutex);
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
/* Remove child from the global task list. */
|
||||
l4lib_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;
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* UTCB management in libl4thread.
|
||||
*
|
||||
* Copyright © 2009 B Labs Ltd.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <l4lib/addr.h>
|
||||
#include <l4lib/thread/utcb-common.h>
|
||||
#include <malloc/malloc.h>
|
||||
#include INC_GLUE(message.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 l4lib_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 l4lib_utcb_desc *desc, unsigned long address)
|
||||
{
|
||||
BUG_ON(id_del(desc->slots, (address - desc->utcb_base)
|
||||
/ UTCB_SIZE) < 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct l4lib_utcb_desc *utcb_new_desc(void)
|
||||
{
|
||||
struct l4lib_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 l4lib_utcb_desc *desc)
|
||||
{
|
||||
/* Return descriptor address */
|
||||
utcb_delete_address((void *)desc->utcb_base, 1);
|
||||
|
||||
/* Free the descriptor */
|
||||
kfree(desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* 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/thread/utcb-common.h>
|
||||
#include <l4lib/utcb.h>
|
||||
|
||||
/* Extern declarations */
|
||||
extern struct l4lib_global_list global_tasks;
|
||||
|
||||
/* Global variables */
|
||||
unsigned long lib_utcb_range_size;
|
||||
|
||||
/* Function definitions */
|
||||
unsigned long get_utcb_addr(struct l4lib_tcb *task)
|
||||
{
|
||||
struct l4lib_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 l4lib_tcb *task)
|
||||
{
|
||||
struct l4lib_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 l4lib_tcb *task;
|
||||
struct l4lib_utcb_desc *udesc;
|
||||
int err;
|
||||
|
||||
/* Create a task. */
|
||||
if (IS_ERR(task = l4_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;
|
||||
}
|
||||
#if 0
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
#endif
|
||||
/* 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