mirror of
https://github.com/drasko/codezero.git
synced 2026-04-10 05:59:07 +02:00
Removed posix container files, moved libl4 to conts, moving linux module to conts as well
This commit is contained in:
51
conts/libl4/src/arm/exregs.c
Normal file
51
conts/libl4/src/arm/exregs.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Generic to arch-specific interface for
|
||||
* exchange_registers()
|
||||
*
|
||||
* Copyright (C) 2008 Bahadir Balban
|
||||
*/
|
||||
#include <l4/macros.h>
|
||||
#include <l4lib/exregs.h>
|
||||
#include INC_GLUE(message.h)
|
||||
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
66
conts/libl4/src/arm/mutex.S
Normal file
66
conts/libl4/src/arm/mutex.S
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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)
|
||||
|
||||
|
||||
222
conts/libl4/src/arm/syscalls.S
Normal file
222
conts/libl4/src/arm/syscalls.S
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Userspace system call interface.
|
||||
*
|
||||
* Copyright (C) 2007 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)
|
||||
|
||||
/*
|
||||
* Reads/manipulates capabilities of a thread, particularly a pager.
|
||||
* @r0 = request type, @r1 = request flags, @r2 = io buffer ptr
|
||||
*/
|
||||
BEGIN_PROC(l4_capability_control)
|
||||
ldr r12, =__l4_capability_control
|
||||
ldr pc, [r12] @ Jump into the SWI
|
||||
/*
|
||||
* The LR_USR points at the return address of this function. The system
|
||||
* call return path directly jumps to LR_USR so we don't even need a
|
||||
* return instruction here.
|
||||
*/
|
||||
END_PROC(l4_capability_control)
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
||||
/*
|
||||
* 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 = struct shm_kdata *kdata
|
||||
*/
|
||||
BEGIN_PROC(l4_space_control)
|
||||
stmfd sp!, {lr}
|
||||
ldr r12, =__l4_space_control
|
||||
mov lr, pc
|
||||
ldr pc, [r12]
|
||||
ldmfd sp!, {pc} @ Restore original lr and return.
|
||||
END_PROC(l4_space_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)
|
||||
|
||||
62
conts/libl4/src/init.c
Normal file
62
conts/libl4/src/init.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Initialise system call offsets and utcb reference.
|
||||
*
|
||||
* Copyright (C) 2007-2009 Bahadir Bilgehan Balban
|
||||
*/
|
||||
#include <l4lib/kip.h>
|
||||
#include <l4lib/arch/syslib.h>
|
||||
#include <l4lib/arch/utcb.h>
|
||||
#include <l4lib/ipcdefs.h>
|
||||
#include <l4/macros.h>
|
||||
#include INC_GLUE(memlayout.h)
|
||||
#include <stdio.h>
|
||||
|
||||
__l4_ipc_t __l4_ipc = 0;
|
||||
__l4_map_t __l4_map = 0;
|
||||
__l4_unmap_t __l4_unmap = 0;
|
||||
__l4_getid_t __l4_getid = 0;
|
||||
__l4_thread_switch_t __l4_thread_switch = 0;
|
||||
__l4_thread_control_t __l4_thread_control = 0;
|
||||
__l4_ipc_control_t __l4_ipc_control = 0;
|
||||
__l4_space_control_t __l4_space_control = 0;
|
||||
__l4_exchange_registers_t __l4_exchange_registers = 0;
|
||||
__l4_container_control_t __l4_container_control = 0;
|
||||
__l4_capability_control_t __l4_capability_control = 0;
|
||||
__l4_time_t __l4_time = 0;
|
||||
__l4_mutex_control_t __l4_mutex_control = 0;
|
||||
|
||||
struct kip *kip;
|
||||
|
||||
/*
|
||||
* Reference to private UTCB of this thread.
|
||||
* Used only for pushing/reading ipc message registers.
|
||||
*/
|
||||
struct utcb **kip_utcb_ref;
|
||||
|
||||
|
||||
void __l4_init(void)
|
||||
{
|
||||
/* Kernel interface page */
|
||||
kip = l4_kernel_interface(0, 0, 0);
|
||||
|
||||
/* Reference to utcb field of KIP */
|
||||
kip_utcb_ref = (struct utcb **)&kip->utcb;
|
||||
|
||||
__l4_ipc = (__l4_ipc_t)kip->ipc;
|
||||
__l4_map = (__l4_map_t)kip->map;
|
||||
__l4_unmap = (__l4_unmap_t)kip->unmap;
|
||||
__l4_getid = (__l4_getid_t)kip->getid;
|
||||
__l4_thread_switch = (__l4_thread_switch_t)kip->thread_switch;
|
||||
__l4_thread_control= (__l4_thread_control_t)kip->thread_control;
|
||||
__l4_ipc_control= (__l4_ipc_control_t)kip->ipc_control;
|
||||
__l4_space_control= (__l4_space_control_t)kip->space_control;
|
||||
__l4_exchange_registers =
|
||||
(__l4_exchange_registers_t)kip->exchange_registers;
|
||||
__l4_capability_control =
|
||||
(__l4_capability_control_t)kip->capability_control;
|
||||
__l4_container_control =
|
||||
(__l4_container_control_t)kip->container_control;
|
||||
__l4_time = (__l4_time_t)kip->time;
|
||||
__l4_mutex_control = (__l4_mutex_control_t)kip->mutex_control;
|
||||
}
|
||||
|
||||
89
conts/libl4/src/mutex.c
Normal file
89
conts/libl4/src/mutex.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Userspace mutex implementation
|
||||
*
|
||||
* Copyright (C) 2009 Bahadir Bilgehan Balban
|
||||
*/
|
||||
#include <l4lib/mutex.h>
|
||||
#include <l4lib/types.h>
|
||||
#include <l4lib/arch/syscalls.h>
|
||||
#include <l4lib/arch/syslib.h>
|
||||
|
||||
/*
|
||||
* NOTES:
|
||||
*
|
||||
* The design is kept as simple as possible.
|
||||
*
|
||||
* l4_mutex_lock() locks an initialized, mutex.
|
||||
* If it contends, it calls the mutex syscall.
|
||||
*
|
||||
* l4_mutex_unlock() releases an acquired mutex.
|
||||
* If there was contention, mutex syscall is called
|
||||
* to resolve by the kernel.
|
||||
*
|
||||
* Internals:
|
||||
*
|
||||
* (1) The kernel creates a waitqueue for every unique
|
||||
* mutex in the system, i.e. every unique physical
|
||||
* address that is contended as a mutex. In that respect
|
||||
* virtual mutex addresses are translated to physical
|
||||
* and checked for match.
|
||||
*
|
||||
* (2) If a mutex is contended, kernel is called by both the
|
||||
* locker and the unlocker (i.e. the lock holder). The syscall
|
||||
* results in a rendezvous and both tasks quit the syscall
|
||||
* synchronised. A rendezvous is necessary because it is not possible
|
||||
* to check lock status and send a WAIT or WAKEUP request to the
|
||||
* kernel atomically from userspace. In other words, a WAKEUP call
|
||||
* would be lost if it arrived before the unsuccessful lock attempt
|
||||
* resulted in a WAIT.
|
||||
*
|
||||
* (3) The unlocker releases the lock after it returns from the syscall.
|
||||
* (4) The locker continuously tries to acquire the lock
|
||||
*
|
||||
* Issues:
|
||||
* - The kernel action is to merely wake up sleepers. If
|
||||
* a new thread acquires the lock meanwhile, all those woken
|
||||
* up threads would have to sleep again.
|
||||
* - All sleepers are woken up (aka thundering herd). This
|
||||
* must be done because if a single task is woken up, there
|
||||
* is no guarantee that that would in turn wake up others.
|
||||
* It might even quit attempting to take the lock.
|
||||
* - Whether this is the best design - time will tell.
|
||||
*/
|
||||
|
||||
extern int __l4_mutex_lock(void *word, l4id_t tid);
|
||||
extern int __l4_mutex_unlock(void *word, l4id_t tid);
|
||||
|
||||
void l4_mutex_init(struct l4_mutex *m)
|
||||
{
|
||||
m->lock = L4_MUTEX_UNLOCKED;
|
||||
}
|
||||
|
||||
int l4_mutex_lock(struct l4_mutex *m)
|
||||
{
|
||||
l4id_t tid = self_tid();
|
||||
int err;
|
||||
|
||||
while(__l4_mutex_lock(m, tid) == L4_MUTEX_CONTENDED) {
|
||||
if ((err = l4_mutex_control(&m->lock, L4_MUTEX_LOCK)) < 0) {
|
||||
printf("%s: Error: %d\n", __FUNCTION__, err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l4_mutex_unlock(struct l4_mutex *m)
|
||||
{
|
||||
l4id_t tid = self_tid();
|
||||
int err;
|
||||
|
||||
if (__l4_mutex_unlock(m, tid) == L4_MUTEX_CONTENDED) {
|
||||
if ((err = l4_mutex_control(&m->lock, L4_MUTEX_UNLOCK)) < 0) {
|
||||
printf("%s: Error: %d\n", __FUNCTION__, err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user