Kernel updates since December 2009

This commit is contained in:
Bahadir Balban
2010-03-25 01:12:40 +02:00
parent 16818191b3
commit 74b5963fcb
487 changed files with 22477 additions and 3857 deletions

View File

@@ -17,7 +17,7 @@ from config.configuration import *
config = configuration_retrieve()
platform = config.platform
arch = config.arch
gcc_cpu_flag = config.gcc_cpu_flag
gcc_arch_flag = config.gcc_arch_flag
LIBL4_RELDIR = 'conts/libl4'
KERNEL_INCLUDE = join(PROJROOT, 'include')
@@ -36,18 +36,17 @@ LIBDEV_RELDIR = 'conts/libdev'
LIBDEV_DIR = join(PROJROOT, LIBDEV_RELDIR)
LIBDEV_LIBPATH = join(join(BUILDDIR, LIBDEV_RELDIR), 'sys-userspace')
LIBDEV_INCLUDE = [join(LIBDEV_DIR, 'uart/include')]
LIBDEV_CCFLAGS = '-DPLATFORM_' + platform.upper()
LIBMEM_RELDIR = 'conts/libmem'
LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR)
LIBMEM_LIBPATH = join(BUILDDIR, LIBMEM_RELDIR)
LIBMEM_INCLUDE = LIBMEM_DIR
env = Environment(CC = config.user_toolchain + 'gcc',
env = Environment(CC = config.toolchain + 'gcc',
# We don't use -nostdinc because sometimes we need standard headers,
# such as stdarg.h e.g. for variable args, as in printk().
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', \
'-Werror', ('-mcpu=' + gcc_cpu_flag), LIBDEV_CCFLAGS],
'-Werror', '-march=' + gcc_arch_flag],
LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"],
ASFLAGS = ['-D__ASSEMBLY__'], \
PROGSUFFIX = '.elf', # The suffix to use for final executable\

View File

@@ -1,8 +1,10 @@
/*
* Main function for this container
*/
#include <l4lib/arch/syslib.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(syslib.h)
#include L4LIB_INC_ARCH(syscalls.h)
#include <l4/api/space.h>
int main(void)

View File

@@ -17,7 +17,7 @@ from config.configuration import *
config = configuration_retrieve()
platform = config.platform
arch = config.arch
gcc_cpu_flag = config.gcc_cpu_flag
gcc_arch_flag = config.gcc_arch_flag
LIBL4_RELDIR = 'conts/libl4'
KERNEL_INCLUDE = join(PROJROOT, 'include')
@@ -36,18 +36,17 @@ LIBDEV_RELDIR = 'conts/libdev'
LIBDEV_DIR = join(PROJROOT, LIBDEV_RELDIR)
LIBDEV_LIBPATH = join(join(BUILDDIR, LIBDEV_RELDIR), 'sys-userspace')
LIBDEV_INCLUDE = [join(LIBDEV_DIR, 'uart/include')]
LIBDEV_CCFLAGS = '-DPLATFORM_' + platform.upper()
LIBMEM_RELDIR = 'conts/libmem'
LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR)
LIBMEM_LIBPATH = join(BUILDDIR, LIBMEM_RELDIR)
LIBMEM_INCLUDE = LIBMEM_DIR
env = Environment(CC = config.user_toolchain + 'gcc',
env = Environment(CC = config.toolchain + 'gcc',
# We don't use -nostdinc because sometimes we need standard headers,
# such as stdarg.h e.g. for variable args, as in printk().
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', \
'-Werror', ('-mcpu=' + gcc_cpu_flag), LIBDEV_CCFLAGS],
'-Werror', '-march=' + gcc_arch_flag],
LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"],\
ASFLAGS = ['-D__ASSEMBLY__'], \
PROGSUFFIX = '.elf', # The suffix to use for final executable
@@ -58,7 +57,7 @@ env = Environment(CC = config.user_toolchain + 'gcc',
CPPPATH = ["#include", KERNEL_INCLUDE, LIBL4_INCLUDE, LIBDEV_INCLUDE, \
LIBC_INCLUDE, LIBMEM_INCLUDE],
LIBPATH = [LIBL4_LIBPATH, LIBDEV_LIBPATH, LIBC_LIBPATH, LIBMEM_LIBPATH],
CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h')
CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h -include l4lib/macros.h')
src = Glob('*.[cS]')
src += Glob('src/*.[cS]')

View File

@@ -1,8 +1,10 @@
/*
* Main function for this container
*/
#include <l4lib/arch/syslib.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(syslib.h)
#include L4LIB_INC_ARCH(syscalls.h)
#include <l4/api/space.h>
extern int print_hello_world(void);

View File

@@ -0,0 +1,2 @@

View File

@@ -0,0 +1,67 @@
# -*- mode: python; coding: utf-8; -*-
#
# Codezero -- Virtualization microkernel for embedded systems.
#
# Copyright © 2009 B Labs Ltd
#
import os, shelve, sys
from os.path import *
PROJRELROOT = '../..'
sys.path.append(PROJRELROOT)
from config.projpaths import *
from config.configuration import *
from config.lib import *
config = configuration_retrieve()
arch = config.arch
platform = config.platform
gcc_arch_flag = config.gcc_arch_flag
LIBL4_RELDIR = 'conts/libl4'
KERNEL_INCLUDE = join(PROJROOT, 'include')
LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR)
LIBL4_INCLUDE = join(LIBL4_DIR, 'include')
LIBL4_LIBPATH = join(BUILDDIR, LIBL4_RELDIR)
# Locally important paths are here
LIBC_RELDIR = 'conts/libc'
LIBC_DIR = join(PROJROOT, LIBC_RELDIR)
LIBC_LIBPATH = join(BUILDDIR, LIBC_RELDIR)
LIBC_INCLUDE = [join(LIBC_DIR, 'include'), \
join(LIBC_DIR, 'include/arch' + '/' + arch)]
LIBDEV_RELDIR = 'conts/libdev'
LIBDEV_DIR = join(PROJROOT, LIBDEV_RELDIR)
LIBDEV_LIBPATH = join(join(BUILDDIR, LIBDEV_RELDIR), 'sys-userspace')
LIBDEV_INCLUDE = [join(LIBDEV_DIR, 'uart/include')]
LIBMEM_RELDIR = 'conts/libmem'
LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR)
LIBMEM_LIBPATH = join(BUILDDIR, LIBMEM_RELDIR)
LIBMEM_INCLUDE = LIBMEM_DIR
env = Environment(CC = config.toolchain + 'gcc',
# We don't use -nostdinc because sometimes we need standard headers,
# such as stdarg.h e.g. for variable args, as in printk().
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', \
'-Werror', '-march=' + gcc_arch_flag],
LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"],\
ASFLAGS = ['-D__ASSEMBLY__'], \
PROGSUFFIX = '.elf', # The suffix to use for final executable\
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path\
LIBS = ['gcc', 'libl4', 'c-userspace', 'libdev-userspace', 'gcc', 'libmalloc',
'c-userspace'], # libgcc.a - This is required for division routines.
CPPPATH = ["#include", KERNEL_INCLUDE, LIBL4_INCLUDE, LIBDEV_INCLUDE, LIBC_INCLUDE, LIBMEM_INCLUDE],
LIBPATH = [LIBL4_LIBPATH, LIBDEV_LIBPATH, LIBC_LIBPATH, LIBMEM_LIBPATH],
CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h')
src = Glob('*.[cS]')
src += Glob('src/*.[cS]')
src += Glob('src/arch/*.[cS]')
objs = env.Object(src)
prog = env.Program('main.elf', objs)
Depends(prog, 'include/linker.lds')

View File

@@ -0,0 +1,21 @@
/*
* Container entry point for pager
*
* Copyright (C) 2007-2009 B Labs Ltd.
*/
#include <l4lib/init.h>
#include <l4lib/utcb.h>
extern void main(void);
void __container_init(void)
{
/* Generic L4 initialisation */
__l4_init();
/* Entry to main */
main();
}

View File

@@ -0,0 +1,6 @@
#ifndef __CAPABILITY_H__
#define __CAPABILITY_H__
int caps_read_all();
#endif /* __CAPABILITY_H__ */

View File

@@ -0,0 +1,7 @@
#ifndef __TESTS_H__
#define __TESTS_H__
int capability_test(void);
#endif /* __TESTS_H__ */

View File

@@ -0,0 +1,19 @@
#ifndef __THREAD_H__
#define __THREAD_H__
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(syslib.h)
#include L4LIB_INC_ARCH(syscalls.h)
#include <l4lib/exregs.h>
#include <l4/api/thread.h>
int thread_create(int (*func)(void *), void *args, unsigned int flags,
struct task_ids *new_ids);
/* For same space */
#define STACK_SIZE 0x1000
#define THREADS_TOTAL 10
#endif /* __THREAD_H__ */

View File

@@ -0,0 +1,81 @@
/*
* Main function for all tests
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <l4/api/errno.h>
#include <container.h>
#include <thread.h>
#include <tests.h>
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(syslib.h)
#include L4LIB_INC_ARCH(syscalls.h)
#include <l4/api/space.h>
int exit_test_thread(void *arg)
{
while (1)
;
//l4_thread_switch(0);
//l4_exit(5);
return 0;
}
int exit_test(void)
{
int ret;
struct task_ids ids;
/* Create and run a new thread */
if ((ret = thread_create(exit_test_thread, 0,
TC_SHARE_SPACE | TC_AS_PAGER,
&ids)) < 0) {
printf("Top-level simple_pager creation failed.\n");
goto out_err;
} else
printf("Thread (%d) created successfully.\n", ids.tid);
// l4_thread_switch(0);
/* Kill it */
printf("Killing Thread (%d).\n", ids.tid);
if ((ret = l4_thread_control(THREAD_DESTROY, &ids)) < 0)
printf("Error: Killing Thread (%d), err = %d\n", ids.tid, ret);
else
printf("Success: Killed Thread (%d)\n", ids.tid);
#if 0
/* Wait on it */
printf("Waiting on Thread (%d) to exit.\n", ids.tid);
if ((ret = l4_thread_control(THREAD_WAIT, &ids)) >= 0)
printf("Success. Paged child returned %d\n", ret);
else
printf("Error. Wait on (%d) failed. err = %d\n",
ids.tid, ret);
#endif
return 0;
out_err:
BUG();
}
int main(void)
{
printf("%s: Container %s started\n",
__CONTAINER__, __CONTAINER_NAME__);
capability_test();
//exit_test();
/* Now quit to demo self-paging quit */
//l4_exit(0);
/* Now quit by null pointer */
// *((int *)0) = 5;
return 0;
}

View File

@@ -0,0 +1,11 @@
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(asm.h)
BEGIN_PROC(local_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
new_thread_exit:
b new_thread_exit @ We infinitely loop for now.
END_PROC(local_setup_new_thread)

View File

@@ -0,0 +1,106 @@
/*
* Capability-related userspace helpers
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <stdio.h>
#include <l4lib/capability/cap_print.h>
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(syscalls.h)
static struct capability cap_array[30];
#if 0
struct cap_group {
struct cap_list virtmem;
struct cap_list physmem;
struct cap_list threadpool;
struct cap_list tctrl;
struct cap_list exregs;
struct cap_list ipc;
struct cap_list mutex;
struct cap_list sched;
struct cap_list mutexpool;
struct cap_list spacepool;
struct cap_list cappool;
};
static inline struct capability *cap_get_thread()
{
}
static inline struct capability *cap_get_space()
{
}
static inline struct capability *cap_get_ipc()
{
}
static inline struct capability *cap_get_virtmem()
{
}
static inline struct capability *cap_get_physmem()
{
}
static inline struct capability *cap_get_physmem(unsigned long phys)
{
}
static inline struct capability *cap_get_virtmem(unsigned long virt)
{
}
static inline struct capability *cap_get_byid(l4id_t id)
{
}
void cap_share_single(struct capability *orig, struct capability *share, l4id_t target, unsigned int flags)
{
}
void cap_grant_single(struct capability *orig, struct capability *share, l4id_t target, unsigned int flags)
{
}
#endif
int caps_read_all(void)
{
int ncaps;
int err;
/* Read number of capabilities */
if ((err = l4_capability_control(CAP_CONTROL_NCAPS,
0, &ncaps)) < 0) {
printf("l4_capability_control() reading # of"
" capabilities failed.\n Could not "
"complete CAP_CONTROL_NCAPS request.\n");
BUG();
}
/* Read all capabilities */
if ((err = l4_capability_control(CAP_CONTROL_READ,
0, cap_array)) < 0) {
printf("l4_capability resource_control() reading of "
"capabilities failed.\n Could not "
"complete CAP_CONTROL_READ_CAPS request.\n");
BUG();
}
//cap_array_print(ncaps, caparray);
return 0;
}

View File

@@ -0,0 +1,149 @@
#include <thread.h>
#include <container.h>
#include <capability.h>
#include <tests.h>
#include <l4/api/errno.h>
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(syslib.h)
#include <l4/api/capability.h>
int simple_pager_thread(void *arg)
{
int err;
int res = *(int *)arg;
struct task_ids ids;
int testres = 0;
l4_getid(&ids);
printf("Thread spawned from pager, \
trying to create new thread.\n");
err = l4_thread_control(THREAD_CREATE |
TC_SHARE_SPACE |
TC_AS_PAGER, &ids);
if (res == 0)
if (err == -ENOCAP ||
err == -ENOMEM) {
printf("Creation failed with %d "
"as expected.\n", err);
testres = 0;
} else {
printf("Creation was supposed to fail "
"with %d or %d, but err = %d\n",
-ENOMEM, -ENOCAP, err);
testres = 1;
}
else
if (err == 0) {
// printf("Creation succeeded as expected.\n");
testres = 0;
} else {
printf("Creation was supposed to succeed, "
"but err = %d\n", err);
testres = 1;
}
/* Destroy thread we created */
if (err == 0 &&
res == 0)
l4_thread_control(THREAD_DESTROY, &ids);
/* Destroy self */
l4_exit(testres);
return 0;
}
int wait_check_test(struct task_ids *ids)
{
int result;
/* Wait for thread to finish */
result = l4_thread_control(THREAD_WAIT, ids);
if (result < 0) {
printf("Waiting on (%d)'s exit failed.\n", ids->tid);
return -1;
} else if (result > 0) {
printf("Top-level test has failed\n");
}
/* Else it is a success */
return 0;
}
int capability_test(void)
{
int err;
struct task_ids ids;
int TEST_MUST_FAIL = 0;
//int TEST_MUST_SUCCEED = 1;
/* Read pager capabilities */
caps_read_all();
/*
* Create new thread that will attempt
* a pager privileged operation
*/
if ((err = thread_create(simple_pager_thread,
&TEST_MUST_FAIL,
TC_SHARE_SPACE, &ids)) < 0) {
printf("Top-level simple_pager creation failed.\n");
goto out_err;
}
printf("waititng for result\n");
/* Wait for test to finish and check result */
if (wait_check_test(&ids) < 0)
goto out_err;
#if 0
/* Destroy test thread */
if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) {
printf("Destruction of top-level simple_pager failed.\n");
BUG();
}
/*
* Share operations with the same thread
* group
*/
if ((err = l4_capability_control(CAP_CONTROL_SHARE,
CAP_SHARE_CONTAINER, 0)) < 0) {
printf("Sharing capability with thread group failed.\n");
goto out_err;
}
/*
* Create new thread that will attempt a pager privileged
* operation. This should succeed as we shared caps with
* the thread group.
*/
if ((err = thread_create(simple_pager_thread,
&TEST_MUST_SUCCEED,
TC_SHARE_SPACE |
TC_SHARE_GROUP, &ids)) < 0) {
printf("Top-level simple_pager creation failed.\n");
goto out_err;
}
/* Wait for test to finish and check result */
if (wait_check_test(&ids) < 0)
goto out_err;
/* Destroy test thread */
if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) {
printf("Destruction of top-level simple_pager failed.\n");
BUG();
}
#endif
printf("Capability Sharing Test -- PASSED --\n");
return 0;
out_err:
printf("Capability Sharing Test -- FAILED --\n");
return 0;
}

View File

@@ -0,0 +1,220 @@
#if 0
int mutex_user_thread(void *arg)
{
/* TODO: Create and access a mutex */
}
int independent_thread(void *arg)
{
/* TODO: Do whatever syscall available */
}
/*
* This example demonstrates how the capability-based
* security model can be bypassed and taken out of the
* way for the sake of implementing an application that
* doesn't worry too much about security.
*
* The benefit is that the user does neither worry about
* capabilities nor using its api to design correctly
* secure systems. The downside is that the system is
* less security-enforced, i.e. all parties must be
* trusted.
*/
int multi_threaded_nocaps_example(void)
{
/*
* We are the first pager with capabilities to
* create new tasks, spaces, in its own container.
*/
pager_read_caps();
/*
* We have all our capabilities private to us.
*
* If we create a new task, it won't be able to
* any kernel operations that we can do, because
* we hold our capabilities privately.
*
* In order to settle all capability access issues
* once and for all threads we will create and manage,
* we share our capabilities with the most global
* collection possible.
*/
/*
* Share all of our capabilities with all threads
* in the same container.
*
* From this point onwards, any thread we create and
* manage (i.e. whose container id is equal to our
* container id) will have the ability to leverage
* all of our capabilities as defined for us at
* configuration time.
*/
l4_cap_share(0, CAP_SHARE_CONTAINER | CAP_SHARE_ALL, self_tid());
/*
* Lets try it.
*
* Create new thread that we don't have any hieararchical
* relationship, i.e. one that is a pager of itself, one
* that runs in a new address space, and in a new thread
* group. All we share is the container.
*/
if ((err = thread_create(independent_thread, 0,
TC_NO_SHARING, &ids)) < 0) {
printf("mutex_user_thread creation failed.\n");
goto out_err;
}
/*
* We can inspect the new thread by doing an ipc to it.
* NOTE:
*
* We are able to send to this thread from the start,
* as we had a container-wide ipc capability defined at
* config-time.
*
* But we would not be able to receive from it, if we
* did not share this capability with the container. It
* would have no rights to do a send to us. But because
* we're in the same container, and we shared our
* capability, it now can.
*/
if ((err = l4_recv(ids->tid, ids->tid, 0)) < 0) {
print_err("%s: L4 IPC Error: %d.\n", __FUNCTION__, fd);
goto out_err;
}
/*
* From this point onwards we can create more threads
* without worrying about whether they have the caps
* to do certain ops, and the caps api. because we shared
* them all at the beginning.
*/
out_err:
BUG();
}
/*
* This example demonstrates how a pager would
* share part of its capabilities on the system
* with its children.
*
* The example includes sharing of a mutex
* capability with a paged-child.
*/
int multi_threaded_capability_sharing_example(void)
{
struct capability *mutex_cap;
int thread_retval;
/*
* We are the first pager with capabilities to
* create new tasks, spaces, in its own container.
*/
pager_read_caps();
/*
* We have all our capabilities private to us.
*
* If we create a new task, it won't be able to
* create and use userspace mutexes, because we
* hold mutex capabilities privately.
*
* Lets try it.
*/
/*
* Create new thread that will attempt
* a mutex operation, and die on us with a
* negative return code if it fails.
*/
if ((err = thread_create(mutex_user_thread, 0,
TC_SHARE_SPACE |
TC_AS_PAGER, &ids)) < 0) {
printf("mutex_user_thread creation failed.\n");
goto out_err;
}
/* Check on how the thread has done */
if ((err = l4_thread_wait_on(ids, &thread_retval)) < 0) {
print("Waiting on thread %d failed. err = %d\n",
ids->tid, err);
goto out_err;
}
if (thread_retval == 0) {
printf("Thread %d returned with success, where "
"we expected failure.\n", ids->tid);
goto out_err;
}
/*
* Therefore, we share our capabilities with a
* collection so that our capabilities may be also
* used by them.
*/
/* Get our private mutex cap */
mutex_cap = cap_get(CAP_TYPE_MUTEX);
/* We have ability to create and use this many mutexes */
printf("%s: We have ability to create/use %d mutexes\n",
self_tid(), mutex_cap->size);
/* Split it */
cap_new = cap_split(mutex_cap, 10, CAP_SPLIT_SIZE);
/*
* Share the split part with paged-children.
*
* From this point onwards, any thread we create and
* manage (i.e. whose pagerid == self_tid()) will have
* the ability to use mutexes, as defined by cap_new
* we created.
*/
l4_cap_share(cap_new, CAP_SHARE_PGGROUP, self_tid());
/*
* Create new thread that will attempt
* a mutex operation, and die on us with a
* negative return code if it fails.
*/
if ((err = thread_create(mutex_user_thread, 0,
TC_SHARE_SPACE |
TC_AS_PAGER, &ids)) < 0) {
printf("mutex_user_thread creation failed.\n");
goto out_err;
}
/* Check on how the thread has done */
if ((err = l4_thread_wait_on(ids, &thread_retval)) < 0) {
printf("Waiting on thread %d failed. err = %d\n",
ids->tid, err);
goto out_err;
}
if (thread_retval < 0) {
printf("Thread %d returned with failure, where "
"we expected success.\n", ids->tid);
goto out_err;
}
out_err:
BUG();
}
#endif

View File

@@ -0,0 +1,73 @@
/*
* Thread creation userspace helpers
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <thread.h>
#include <l4/api/errno.h>
char stack[THREADS_TOTAL][STACK_SIZE] ALIGN(8);
char *__stack_ptr = &stack[1][0];
char utcb[THREADS_TOTAL][UTCB_SIZE] ALIGN(8);
char *__utcb_ptr = &utcb[1][0];
extern void local_setup_new_thread(void);
int thread_create(int (*func)(void *), void *args, unsigned int flags,
struct task_ids *new_ids)
{
struct task_ids ids;
struct exregs_data exregs;
int err;
l4_getid(&ids);
/* Shared space only */
if (!(TC_SHARE_SPACE & flags)) {
printf("%s: This function allows only "
"shared space thread creation.\n",
__FUNCTION__);
return -EINVAL;
}
/* Create thread */
if ((err = l4_thread_control(THREAD_CREATE | flags, &ids)) < 0)
return err;
/* Check if more stack/utcb available */
if ((unsigned long)__utcb_ptr ==
(unsigned long)&utcb[THREADS_TOTAL][0])
return -ENOMEM;
if ((unsigned long)__stack_ptr ==
(unsigned long)&stack[THREADS_TOTAL][0])
return -ENOMEM;
/* First word of new stack is arg */
*(((unsigned int *)__stack_ptr) -1) = (unsigned int)args;
/* Second word of new stack is function address */
*(((unsigned int *)__stack_ptr) -2) = (unsigned int)func;
/* Setup new thread pc, sp, utcb */
memset(&exregs, 0, sizeof(exregs));
exregs_set_stack(&exregs, (unsigned long)__stack_ptr);
exregs_set_utcb(&exregs, (unsigned long)__utcb_ptr);
exregs_set_pc(&exregs, (unsigned long)local_setup_new_thread);
if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0)
return err;
/* Update utcb, stack pointers */
__stack_ptr += STACK_SIZE;
__utcb_ptr += UTCB_SIZE;
/* Start the new thread */
if ((err = l4_thread_control(THREAD_RUN, &ids)) < 0)
return err;
memcpy(new_ids, &ids, sizeof(ids));
return 0;
}

View File

@@ -17,7 +17,7 @@ from config.configuration import *
config = configuration_retrieve()
platform = config.platform
arch = config.arch
gcc_cpu_flag = config.gcc_cpu_flag
gcc_arch_flag = config.gcc_arch_flag
LIBL4_RELDIR = 'conts/libl4'
KERNEL_INCLUDE = join(PROJROOT, 'include')
@@ -36,18 +36,17 @@ LIBDEV_RELDIR = 'conts/libdev'
LIBDEV_DIR = join(PROJROOT, LIBDEV_RELDIR)
LIBDEV_LIBPATH = join(join(BUILDDIR, LIBDEV_RELDIR), 'sys-userspace')
LIBDEV_INCLUDE = [join(LIBDEV_DIR, 'uart/include')]
LIBDEV_CCFLAGS = '-DPLATFORM_' + platform.upper()
LIBMEM_RELDIR = 'conts/libmem'
LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR)
LIBMEM_LIBPATH = join(BUILDDIR, LIBMEM_RELDIR)
LIBMEM_INCLUDE = LIBMEM_DIR
env = Environment(CC = config.user_toolchain + 'gcc',
env = Environment(CC = config.toolchain + 'gcc',
# We don't use -nostdinc because sometimes we need standard headers,
# such as stdarg.h e.g. for variable args, as in printk().
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', \
'-Werror', ('-mcpu=' + gcc_cpu_flag), LIBDEV_CCFLAGS],
'-Werror', '-march=' + gcc_arch_flag],
LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"],
ASFLAGS = ['-D__ASSEMBLY__'],
PROGSUFFIX = '.elf', # The suffix to use for final executable

View File

@@ -1,8 +1,9 @@
/*
* Main function for this container
*/
#include <l4lib/arch/syslib.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(syslib.h)
#include L4LIB_INC_ARCH(syscalls.h)
#include <l4/api/space.h>
#include <l4lib/thread/thread.h>

View File

@@ -18,7 +18,7 @@ from configure import *
config = configuration_retrieve()
arch = config.arch
platform = config.platform
gcc_cpu_flag = config.gcc_cpu_flag
gcc_arch_flag = config.gcc_arch_flag
# Wrapper library for system calls
LIBL4_RELDIR = 'conts/libl4'
@@ -37,20 +37,18 @@ LIBC_INCLUDE = [join(LIBC_DIR, 'include'), \
LIBDEV_RELDIR = 'conts/libdev'
LIBDEV_DIR = join(PROJROOT, LIBDEV_RELDIR)
LIBDEV_LIBPATH = join(join(BUILDDIR, LIBDEV_RELDIR), 'sys-userspace')
LIBDEV_INCLUDE = [join(LIBDEV_DIR, 'uart/include'),
join(LIBDEV_DIR, 'timer/sp804/include')]
LIBDEV_CCFLAGS = '-DPLATFORM_' + platform.upper()
LIBDEV_INCLUDE = join(LIBDEV_DIR, 'include')
LIBMEM_RELDIR = 'conts/libmem'
LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR)
LIBMEM_LIBPATH = join(BUILDDIR, LIBMEM_RELDIR)
LIBMEM_INCLUDE = LIBMEM_DIR
env = Environment(CC = config.user_toolchain + 'gcc',
env = Environment(CC = config.toolchain + 'gcc',
# We don't use -nostdinc because sometimes we need standard headers,
# such as stdarg.h e.g. for variable args, as in printk().
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', \
'-Werror', ('-mcpu=' + gcc_cpu_flag), LIBDEV_CCFLAGS], \
'-Werror', '-march=' + gcc_arch_flag], \
LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"],\
ASFLAGS = ['-D__ASSEMBLY__'], \
PROGSUFFIX = '.elf', # The suffix to use for final executable

View File

@@ -1,8 +1,9 @@
#ifndef __THREAD_H__
#define __THREAD_H__
#include <l4lib/arch/syslib.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(syslib.h)
#include L4LIB_INC_ARCH(syscalls.h)
#include <l4lib/exregs.h>
#include <l4/api/thread.h>

View File

@@ -8,15 +8,76 @@
#include <l4/lib/list.h>
#include <l4lib/types.h>
/* Structure representing the sleeping tasks */
struct sleeper_task {
struct link list;
l4id_t tid; /* tid of sleeping task */
int retval; /* return value on wakeup */
};
/* list of tasks to be woken up */
struct wake_task_list {
struct link head;
struct link *end; /* optimization */
struct l4_mutex lock; /* lock for sanity of head */
};
#define BUCKET_BASE_LEVEL_BITS 8
#define BUCKET_HIGHER_LEVEL_BITS 6
#define BUCKET_BASE_LEVEL_SIZE (1 << BUCKET_BASE_LEVEL_BITS)
#define BUCKET_HIGHER_LEVEL_SIZE (1 << BUCKET_HIGHER_LEVEL_BITS)
#define BUCKET_BASE_LEVEL_MASK 0xFF
#define BUCKET_HIGHER_LEVEL_MASK 0x3F
/*
* Web of sleeping tasks
* based on timer wheel base algorithm
*/
struct sleeper_task_bucket {
struct link bucket_level0[BUCKET_BASE_LEVEL_SIZE];
struct link bucket_level1[BUCKET_HIGHER_LEVEL_SIZE];
struct link bucket_level2[BUCKET_HIGHER_LEVEL_SIZE];
struct link bucket_level3[BUCKET_HIGHER_LEVEL_SIZE];
struct link bucket_level4[BUCKET_HIGHER_LEVEL_SIZE];
};
/* Macros to extract bucket levels */
#define GET_BUCKET_LEVEL4(x) \
((x >> (BUCKET_BASE_LEVEL_BITS + (3 * BUCKET_HIGHER_LEVEL_BITS))) & \
BUCKET_HIGHER_LEVEL_MASK)
#define GET_BUCKET_LEVEL3(x) \
((x >> (BUCKET_BASE_LEVEL_BITS + (2 * BUCKET_HIGHER_LEVEL_BITS))) & \
BUCKET_HIGHER_LEVEL_MASK)
#define GET_BUCKET_LEVEL2(x) \
((x >> (BUCKET_BASE_LEVEL_BITS + (1 * BUCKET_HIGHER_LEVEL_BITS))) & \
BUCKET_HIGHER_LEVEL_MASK)
#define GET_BUCKET_LEVEL1(x) \
((x >> BUCKET_BASE_LEVEL_BITS) & BUCKET_HIGHER_LEVEL_MASK)
#define GET_BUCKET_LEVEL0(x) (x & BUCKET_BASE_LEVEL_MASK)
/* Macros to find bucket level */
#define IS_IN_LEVEL0_BUCKET(x) \
(x < (1 << BUCKET_BASE_LEVEL_BITS))
#define IS_IN_LEVEL1_BUCKET(x) \
(x < (1 << (BUCKET_BASE_LEVEL_BITS + BUCKET_HIGHER_LEVEL_BITS)))
#define IS_IN_LEVEL2_BUCKET(x) \
(x < (1 << (BUCKET_BASE_LEVEL_BITS + (2 * BUCKET_HIGHER_LEVEL_BITS))))
#define IS_IN_LEVEL3_BUCKET(x) \
(x < (1 << (BUCKET_BASE_LEVEL_BITS + (3 * BUCKET_HIGHER_LEVEL_BITS))))
/*
* Timer structure
* TODO: Keep timer 32 bit for time being,
* we will make it 64 in future
*/
struct timer {
int slot; /* Notify slot on utcb */
unsigned int base; /* Virtual base address */
u64 count; /* Counter */
struct link task_list; /* List of sleepers */
struct l4_mutex lock; /* Lock for structure */
unsigned long base; /* Virtual base address */
unsigned int count; /* Counter/jiffies */
struct sleeper_task_bucket task_list; /* List of sleeping tasks */
struct l4_mutex lock; /* Lock for sleeper_task_bucket */
struct capability cap; /* Capability describing timer */
};

View File

@@ -1,34 +1,38 @@
/*
* Timer service for userspace
*/
#include <l4lib/arch/syslib.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/addr.h>
#include <l4lib/exregs.h>
#include <l4lib/lib/addr.h>
#include <l4lib/irq.h>
#include <l4lib/ipcdefs.h>
#include <l4/api/errno.h>
#include <l4/api/irq.h>
#include <l4/api/capability.h>
#include <l4/generic/cap-types.h>
#include <l4/api/space.h>
#include <malloc/malloc.h>
#include <l4lib/capability/cap_print.h>
#include <container.h>
#include "sp804_timer.h"
#include <linker.h>
#include <timer.h>
#include <thread.h>
#include <libdev/timer.h>
/* Frequency of timer in MHz */
#define TIMER_FREQUENCY 1
#define TIMERS_TOTAL 1
/* Capabilities of this service */
static struct capability caparray[32];
static int total_caps = 0;
/* Total number of timer chips being handled by us */
#define TIMERS_TOTAL 1
static struct timer timer[TIMERS_TOTAL];
/* Deafult timer to be used for sleep/wake etc purposes */
#define SLEEP_WAKE_TIMER 0
/* tasks whose sleep time has finished */
struct wake_task_list wake_tasks;
/* tid of handle_request thread */
l4id_t tid_ipc_handler;
int cap_read_all()
{
int ncaps;
@@ -52,7 +56,6 @@ int cap_read_all()
"complete CAP_CONTROL_READ_CAPS request.\n");
BUG();
}
cap_array_print(total_caps, caparray);
return 0;
}
@@ -74,6 +77,89 @@ int cap_share_all_with_space()
return 0;
}
/*
* Initialize timer devices
*/
void timer_struct_init(struct timer* timer, unsigned long base)
{
timer->base = base;
timer->count = 0;
timer->slot = 0;
l4_mutex_init(&timer->lock);
for (int i = 0; i < BUCKET_BASE_LEVEL_SIZE ; ++i) {
link_init(&timer->task_list.bucket_level0[i]);
}
for (int i = 0; i < BUCKET_HIGHER_LEVEL_SIZE ; ++i) {
link_init(&timer->task_list.bucket_level1[i]);
link_init(&timer->task_list.bucket_level2[i]);
link_init(&timer->task_list.bucket_level3[i]);
link_init(&timer->task_list.bucket_level4[i]);
}
}
/*
* Initialize wake list head structure
*/
void wake_task_list_init(void)
{
link_init(&wake_tasks.head);
wake_tasks.end = &wake_tasks.head;
l4_mutex_init(&wake_tasks.lock);
}
/*
* Allocate new sleeper task struct
*/
struct sleeper_task *new_sleeper_task(l4id_t tid, int ret)
{
struct sleeper_task *task;
/* May be we can prepare a cache for timer_task structs */
task = (struct sleeper_task *)kzalloc(sizeof(struct sleeper_task));
link_init(&task->list);
task->tid = tid;
task->retval = ret;
return task;
}
void free_sleeper_task(struct sleeper_task *task)
{
kfree(task);
task = NULL;
}
/*
* Find the bucket list correspongding to seconds value
*/
struct link* find_bucket_list(unsigned long seconds)
{
struct link *vector;
struct sleeper_task_bucket *bucket;
bucket = &timer[SLEEP_WAKE_TIMER].task_list;
/*
* TODO: Check if we have already surpassed seconds
*/
if (IS_IN_LEVEL0_BUCKET(seconds)) {
vector = &bucket->bucket_level0[GET_BUCKET_LEVEL0(seconds)];
} else if (IS_IN_LEVEL1_BUCKET(seconds)) {
vector = &bucket->bucket_level1[GET_BUCKET_LEVEL1(seconds)];
} else if (IS_IN_LEVEL2_BUCKET(seconds)) {
vector = &bucket->bucket_level2[GET_BUCKET_LEVEL2(seconds)];
} else if (IS_IN_LEVEL3_BUCKET(seconds)) {
vector = &bucket->bucket_level3[GET_BUCKET_LEVEL3(seconds)];
} else {
vector = &bucket->bucket_level4[GET_BUCKET_LEVEL4(seconds)];
}
return vector;
}
/*
* Scans for up to TIMERS_TOTAL timer devices in capabilities.
*/
@@ -100,16 +186,18 @@ int timer_probe_devices(void)
return 0;
}
/*
* Irq handler for timer interrupts
*/
int timer_irq_handler(void *arg)
{
int err;
struct timer *timer = (struct timer *)arg;
struct link *vector;
const int slot = 0;
/* Initialise timer */
sp804_init(timer->base, SP804_TIMER_RUNMODE_PERIODIC,
SP804_TIMER_WRAPMODE_WRAPPING,
SP804_TIMER_WIDTH32BIT, SP804_TIMER_IRQENABLE);
timer_init(timer->base);
/* Register self for timer irq, using notify slot 0 */
if ((err = l4_irq_control(IRQ_CONTROL_REGISTER, slot,
@@ -120,40 +208,105 @@ int timer_irq_handler(void *arg)
}
/* Enable Timer */
sp804_enable(timer->base, 1);
timer_start(timer->base);
/* Handle irqs forever */
while (1) {
int count;
struct link *task_list;
/* Block on irq */
count = l4_irq_wait(slot, timer->cap.irq);
if((count = l4_irq_wait(slot, timer->cap.irq)) < 0) {
printf("l4_irq_wait() returned with negative value\n");
BUG();
}
/* Update timer count */
//printf("Got irq(count 0x%x)\n", timer->count);
/*
* Update timer count
* TODO: Overflow check, we have 1 interrupt/sec from timer
* with 32bit count it will take 9years to overflow
*/
timer->count += count;
/* Print both counter and number of updates on count */
printf("Timer count: %lld, current update: %d\n",
timer->count, count);
/* find bucket list of taks to be woken for current count */
vector = find_bucket_list(timer->count);
if (!list_empty(vector)) {
/* Removing tasks from sleeper list */
l4_mutex_lock(&timer[SLEEP_WAKE_TIMER].lock);
task_list = list_detach(vector);
l4_mutex_unlock(&timer[SLEEP_WAKE_TIMER].lock);
/* Add tasks to wake_task_list */
l4_mutex_lock(&wake_tasks.lock);
list_attach(task_list,
&wake_tasks.head, wake_tasks.end);
l4_mutex_unlock(&wake_tasks.lock);
/*
* Send ipc to handle_request
* thread to send wake signals
*/
printf("sending ipc %d to thread %d\n", L4_IPC_TAG_TIMER_WAKE_THREADS, tid_ipc_handler);
l4_send(tid_ipc_handler,L4_IPC_TAG_TIMER_WAKE_THREADS);
}
}
}
/*
* Helper routine to wake tasks from wake list
*/
void task_wake(void)
{
struct sleeper_task *struct_ptr, *temp_ptr;
int ret;
if (!list_empty(&wake_tasks.head)) {
list_foreach_removable_struct(struct_ptr, temp_ptr,
&wake_tasks.head, list) {
/* Remove task from wake list */
l4_mutex_lock(&wake_tasks.lock);
list_remove(&struct_ptr->list);
l4_mutex_unlock(&wake_tasks.lock);
/* Set sender correctly */
l4_set_sender(struct_ptr->tid);
#if 0
printf("waking thread at time %x\n",
(unsigned int)timer[SLEEP_WAKE_TIMER].count);
#endif
/* send wake ipc */
if ((ret = l4_ipc_return(struct_ptr->retval)) < 0) {
printf("%s: IPC return error: %d.\n",
__FUNCTION__, ret);
BUG();
}
/* free allocated sleeper task struct */
free_sleeper_task(struct_ptr);
}
}
/* If wake list is empty set end = start */
if (list_empty(&wake_tasks.head))
wake_tasks.end = &wake_tasks.head;
}
int timer_setup_devices(void)
{
struct task_ids irq_tids;
int err;
for (int i = 0; i < TIMERS_TOTAL; i++) {
/* Get one page from address pool */
timer[i].base = (unsigned long)l4_new_virtual(1);
timer[i].count = 0;
link_init(&timer[i].task_list);
l4_mutex_init(&timer[i].lock);
/* initialize timer */
timer_struct_init(&timer[i],(unsigned long)l4_new_virtual(1) );
/* Map timer to a virtual address region */
if (IS_ERR(l4_map((void *)__pfn_to_addr(timer[i].cap.start),
(void *)timer[i].base, timer[i].cap.size,
MAP_USR_IO_FLAGS,
MAP_USR_IO,
self_tid()))) {
printf("%s: FATAL: Failed to map TIMER device "
"%d to a virtual address\n",
@@ -181,7 +334,16 @@ int timer_setup_devices(void)
return 0;
}
/*
* Declare a statically allocated char buffer
* with enough bitmap size to cover given size
*/
#define DECLARE_IDPOOL(name, size) \
char name[(sizeof(struct id_pool) + ((size >> 12) >> 3))]
#define PAGE_POOL_SIZE SZ_1MB
static struct address_pool device_vaddr_pool;
DECLARE_IDPOOL(device_id_pool, PAGE_POOL_SIZE);
/*
* Initialize a virtual address pool
@@ -210,9 +372,9 @@ void init_vaddr_pool(void)
* addresses from this pool.
*/
address_pool_init(&device_vaddr_pool,
page_align_up(__end),
__pfn_to_addr(caparray[i].end),
TIMERS_TOTAL);
(struct id_pool *)&device_id_pool,
page_align_up(__end),
__pfn_to_addr(caparray[i].end));
return;
} else
goto out_err;
@@ -231,68 +393,25 @@ void *l4_new_virtual(int npages)
return address_new(&device_vaddr_pool, npages, PAGE_SIZE);
}
#if 0
struct timer_task *get_timer_task(l4id_t tgid)
/*
* Got request for sleep for seconds,
* right now max sleep allowed is 2^32 sec
*/
void task_sleep(l4id_t tid, unsigned long seconds, int ret)
{
/* May be we can prepare a cache for timer_task structs */
struct timer_task *task = (struct timer_task *)kzalloc(sizeof(struct timer_task));
struct sleeper_task *task = new_sleeper_task(tid, ret);
struct link *vector;
link_init(&task->list);
task->tgid = tgid;
task->wait_count = timer[0].count;
/* can overflow happen here?, timer is in 32bit mode */
seconds += timer[SLEEP_WAKE_TIMER].count;
return task;
vector = find_bucket_list(seconds);
l4_mutex_lock(&timer[SLEEP_WAKE_TIMER].lock);
list_insert(&task->list, vector);
l4_mutex_unlock(&timer[SLEEP_WAKE_TIMER].lock);
}
void free_timer_task(struct timer_task *task)
{
kfree(task);
}
void timer_irq_handler(void)
{
struct timer_task *struct_ptr, *temp_ptr;
timer[0].count += 1;
/*
* FIXME:
* Traverse through the sleeping process list and
* wake any process if required, we need to put this part in bottom half
*/
list_foreach_removable_struct(struct_ptr, temp_ptr, &timer[0].tasklist, list)
if (struct_ptr->wait_count == timer[0].count) {
/* Remove task from list */
l4_mutex_lock(&timer[0].lock);
list_remove(&struct_ptr->list);
l4_mutex_unlock(&timer[0].lock);
/* wake the sleeping process, send wake ipc */
free_timer_task(struct_ptr);
}
}
int timer_gettime(void)
{
return timer[0].count;
}
void timer_sleep(l4id_t tgid, int sec)
{
struct timer_task *task = get_timer_task(tgid);
/* Check for overflow */
task->wait_count += (sec * 1000000);
l4_mutex_lock(&timer[0].lock);
list_insert_tail(&task->list, &timer[0].tasklist);
l4_mutex_unlock(&timer[0].lock);
}
#endif
void handle_requests(void)
{
u32 mr[MR_UNUSED_TOTAL];
@@ -300,10 +419,9 @@ void handle_requests(void)
u32 tag;
int ret;
printf("%s: Initiating ipc.\n", __CONTAINER__);
if ((ret = l4_receive(L4_ANYTHREAD)) < 0) {
printf("%s: %s: IPC Error: %d. Quitting...\n", __CONTAINER__,
__FUNCTION__, ret);
printf("%s: %s: IPC Error: %d. Quitting...\n",
__CONTAINER__, __FUNCTION__, ret);
BUG();
}
@@ -327,13 +445,35 @@ void handle_requests(void)
* inside the current container
*/
switch (tag) {
/* Return time in seconds, since the timer was started */
case L4_IPC_TAG_TIMER_GETTIME:
//mr[0] = timer_gettime();
mr[0] = timer[SLEEP_WAKE_TIMER].count;
/* Reply */
if ((ret = l4_ipc_return(ret)) < 0) {
printf("%s: IPC return error: %d.\n", __FUNCTION__, ret);
BUG();
}
break;
case L4_IPC_TAG_TIMER_SLEEP:
//timer_sleep(senderid, mr[0]);
/* TODO: Halt the caller for mr[0] seconds */
printf("%s: Got sleep request from thread 0x%x, duration %d\n", __CONTAINER_NAME__,
senderid, mr[0]);
if (mr[0] > 0) {
task_sleep(senderid, mr[0], ret);
}
else {
if ((ret = l4_ipc_return(ret)) < 0) {
printf("%s: IPC return error: %d.\n",
__FUNCTION__, ret);
BUG();
}
}
break;
/* Intra container ipc by irq_thread */
case L4_IPC_TAG_TIMER_WAKE_THREADS:
task_wake();
break;
default:
@@ -342,12 +482,6 @@ void handle_requests(void)
"0x%x\n", __CONTAINER__, senderid,
__cid(senderid), tag);
}
/* Reply */
if ((ret = l4_ipc_return(ret)) < 0) {
printf("%s: IPC return error: %d.\n", __FUNCTION__, ret);
BUG();
}
}
/*
@@ -408,12 +542,17 @@ void main(void)
BUG();
}
/* initialise timed_out_task list */
wake_task_list_init();
/* Map and initialize timer devices */
timer_setup_devices();
/* Set the tid of ipc handler */
tid_ipc_handler = self_tid();
/* Listen for timer requests */
while (1)
handle_requests();
}

View File

@@ -1,5 +1,5 @@
#include <l4lib/arch/asm.h>
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(asm.h)
BEGIN_PROC(local_setup_new_thread)
ldr r0, [sp, #-4]! @ Load first argument.

View File

@@ -10,6 +10,7 @@ char stack[THREADS_TOTAL][STACK_SIZE] ALIGN(8);
char *__stack_ptr = &stack[1][0];
char utcb[THREADS_TOTAL][UTCB_SIZE] ALIGN(8);
//char utcb[THREADS_TOTAL][0x1000] ALIGN(0x1000);
char *__utcb_ptr = &utcb[1][0];
extern void local_setup_new_thread(void);
@@ -25,7 +26,7 @@ int thread_create(int (*func)(void *), void *args, unsigned int flags,
/* Shared space only */
if (!(TC_SHARE_SPACE & flags)) {
printf("%s: This function allows only "
printf("%s: Warning - This function allows only "
"shared space thread creation.\n",
__FUNCTION__);
return -EINVAL;
@@ -61,6 +62,7 @@ int thread_create(int (*func)(void *), void *args, unsigned int flags,
/* Update utcb, stack pointers */
__stack_ptr += STACK_SIZE;
__utcb_ptr += UTCB_SIZE;
//__utcb_ptr += 0x1000;
/* Start the new thread */
if ((err = l4_thread_control(THREAD_RUN, &ids)) < 0)

View File

@@ -17,7 +17,7 @@ from config.configuration import *
config = configuration_retrieve()
platform = config.platform
arch = config.arch
gcc_cpu_flag = config.gcc_cpu_flag
gcc_arch_flag = config.gcc_arch_flag
LIBL4_RELDIR = 'conts/libl4'
KERNEL_INCLUDE = join(PROJROOT, 'include')
@@ -35,8 +35,7 @@ LIBC_INCLUDE = [join(LIBC_DIR, 'include'), \
LIBDEV_RELDIR = 'conts/libdev'
LIBDEV_DIR = join(PROJROOT, LIBDEV_RELDIR)
LIBDEV_LIBPATH = join(join(BUILDDIR, LIBDEV_RELDIR), 'sys-userspace')
LIBDEV_INCLUDE = [join(LIBDEV_DIR, 'uart/include')]
LIBDEV_CCFLAGS = '-DPLATFORM_' + platform.upper()
LIBDEV_INCLUDE = join(LIBDEV_DIR, 'include')
# FIXME: Add these to autogenerated SConstruct !!!
LIBMEM_RELDIR = 'conts/libmem'
@@ -44,16 +43,17 @@ LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR)
LIBMEM_LIBPATH = join(BUILDDIR, LIBMEM_RELDIR)
LIBMEM_INCLUDE = LIBMEM_DIR
env = Environment(CC = config.user_toolchain + 'gcc',
env = Environment(CC = config.toolchain + 'gcc',
# We don't use -nostdinc because sometimes we need standard headers,
# such as stdarg.h e.g. for variable args, as in printk().
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', \
'-Werror', ('-mcpu=' + gcc_cpu_flag), LIBDEV_CCFLAGS],
'-Werror', '-march=' + gcc_arch_flag],
LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"],
ASFLAGS = ['-D__ASSEMBLY__'], \
PROGSUFFIX = '.elf', # The suffix to use for final executable\
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path\
LIBS = ['gcc', 'libl4', 'libmalloc', 'c-userspace', 'libdev-userspace', 'gcc', 'c-userspace'], # libgcc.a - This is required for division routines.
LIBS = ['gcc', 'libl4', 'libmalloc', 'c-userspace', 'libdev-userspace',
'gcc', 'c-userspace'], # libgcc.a - This is required for division routines.
CPPPATH = ["#include", KERNEL_INCLUDE, LIBL4_INCLUDE, LIBDEV_INCLUDE, LIBC_INCLUDE, LIBMEM_INCLUDE],
LIBPATH = [LIBL4_LIBPATH, LIBDEV_LIBPATH, LIBC_LIBPATH, LIBMEM_LIBPATH],
CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h')

View File

@@ -1,25 +1,28 @@
/*
* UART service for userspace
*/
#include <l4lib/arch/syslib.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/addr.h>
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(syslib.h)
#include L4LIB_INC_ARCH(syscalls.h)
#include <l4lib/exregs.h>
#include <l4lib/lib/addr.h>
#include <l4lib/ipcdefs.h>
#include <l4/api/errno.h>
#include <l4/api/capability.h>
#include <l4/generic/cap-types.h>
#include <l4/api/space.h>
#include <l4lib/capability/cap_print.h>
#include <container.h>
#include <pl011_uart.h> /* FIXME: Its best if this is <libdev/uart/pl011.h> */
#include <linker.h>
#include <uart.h>
#include <libdev/uart.h>
#define UARTS_TOTAL 3
/* Capabilities of this service */
static struct capability caparray[32];
static int total_caps = 0;
struct capability uart_cap[UARTS_TOTAL];
/* Number of UARTS to be managed by this service */
#define UARTS_TOTAL 1
static struct uart uart[UARTS_TOTAL];
int cap_read_all()
{
@@ -45,7 +48,21 @@ int cap_read_all()
BUG();
}
//cap_array_print(total_caps, caparray);
return 0;
}
int cap_share_all_with_space()
{
int err;
/* Share all capabilities */
if ((err = l4_capability_control(CAP_CONTROL_SHARE,
CAP_SHARE_ALL_SPACE, 0)) < 0) {
printf("l4_capability_control() sharing of "
"capabilities failed.\n Could not "
"complete CAP_CONTROL_SHARE request. err=%d\n", err);
BUG();
}
return 0;
}
@@ -61,8 +78,8 @@ int uart_probe_devices(void)
/* Match device type */
if (cap_devtype(&caparray[i]) == CAP_DEVTYPE_UART) {
/* Copy to correct device index */
memcpy(&uart_cap[cap_devnum(&caparray[i]) - 1],
&caparray[i], sizeof(uart_cap[0]));
memcpy(&uart[cap_devnum(&caparray[i]) - 1].cap,
&caparray[i], sizeof(uart[0].cap));
uarts++;
}
}
@@ -75,7 +92,7 @@ int uart_probe_devices(void)
return 0;
}
static struct pl011_uart uart[UARTS_TOTAL];
static struct uart uart[UARTS_TOTAL];
int uart_setup_devices(void)
{
@@ -84,24 +101,32 @@ int uart_setup_devices(void)
uart[i].base = (unsigned long)l4_new_virtual(1);
/* Map uart to a virtual address region */
if (IS_ERR(l4_map((void *)__pfn_to_addr(uart_cap[i].start),
(void *)uart[i].base, uart_cap[i].size,
MAP_USR_IO_FLAGS,
self_tid()))) {
if (IS_ERR(l4_map((void *)__pfn_to_addr(uart[i].cap.start),
(void *)uart[i].base, uart[i].cap.size,
MAP_USR_IO, self_tid()))) {
printf("%s: FATAL: Failed to map UART device "
"%d to a virtual address\n",
__CONTAINER_NAME__,
cap_devnum(&uart_cap[i]));
cap_devnum(&uart[i].cap));
BUG();
}
/* Initialize uart */
pl011_initialise(&uart[i]);
uart_init(uart[i].base);
}
return 0;
}
/*
* Declare a statically allocated char buffer
* with enough bitmap size to cover given size
*/
#define DECLARE_IDPOOL(name, size) \
char name[(sizeof(struct id_pool) + ((size >> 12) >> 3))]
#define PAGE_POOL_SIZE SZ_1MB
static struct address_pool device_vaddr_pool;
DECLARE_IDPOOL(device_id_pool, PAGE_POOL_SIZE);
/*
* Initialize a virtual address pool
@@ -130,9 +155,9 @@ void init_vaddr_pool(void)
* addresses from this pool.
*/
address_pool_init(&device_vaddr_pool,
(struct id_pool *)&device_id_pool,
page_align_up(__end),
__pfn_to_addr(caparray[i].end),
UARTS_TOTAL);
__pfn_to_addr(caparray[i].end));
return;
} else
goto out_err;
@@ -153,16 +178,12 @@ void *l4_new_virtual(int npages)
void uart_generic_tx(char c, int devno)
{
pl011_tx_char(uart[devno].base, c);
uart_tx_char(uart[devno].base, c);
}
char uart_generic_rx(int devno)
{
char c;
pl011_rx_char(uart[devno].base, &c);
return c;
return uart_rx_char(uart[devno].base);
}
void handle_requests(void)
@@ -268,6 +289,9 @@ void main(void)
/* Read all capabilities */
cap_read_all();
/* Share all with space */
cap_share_all_with_space();
/* Scan for uart devices in capabilities */
uart_probe_devices();

View File

@@ -18,17 +18,18 @@ from config.projpaths import *
Import('env', 'arch', 'type')
variant = type
# Needed by fputc(), for declaration of pl011_uart_tx()
LIBDEV_PATH = join(PROJROOT, 'conts/libdev')
LIBDEV_INCPATH = [LIBDEV_PATH + '/uart/include']
# Needed by fputc(), for declaration of uart_tx()
LIBDEV_RELDIR = 'conts/libdev'
LIBDEV_DIR = join(PROJROOT, LIBDEV_RELDIR)
LIBDEV_INC = join(LIBDEV_DIR, 'include')
e = env.Clone()
e.Append(CPPPATH = ['include', 'include/sys-' + variant + '/arch-' + arch,
LIBDEV_INCPATH],
CCFLAGS = '-nostdinc')
e.Append(CPPPATH = ['include', 'include/sys-' + variant + \
'/arch-' + arch, LIBDEV_INC],
CCFLAGS = ['-nostdinc'])
source = \
Glob('src/*.c') + \
Glob('src/*.[cS]') + \
Glob('src/sys-' + variant + '/*.c') + \
Glob('src/sys-' + variant + '/arch-' + arch + '/*.c') + \
Glob('src/arch-' + arch + '/*.c') + \

50
conts/libc/SConstruct Normal file
View File

@@ -0,0 +1,50 @@
# -*- mode: python; coding: utf-8; -*-
#
# Codezero -- a microkernel for embedded systems.
#
# Copyright © 2009 B Labs Ltd
#
import os, sys
PROJRELROOT = '../..'
sys.path.append(PROJRELROOT)
from config.projpaths import *
from config.configuration import *
config = configuration_retrieve()
gcc_arch_flag = config.gcc_arch_flag
arch = config.arch
# We assume we are compiling for userspace.
# variant can be specified from cmdline using
# scons variant=xxx
variant = ARGUMENTS.get('variant', 'userspace')
print '\nCompiling for variant: ' + variant + '\n'
# Needed by fputc(), for declaration of uart_tx()
LIBDEV_RELDIR = 'conts/libdev'
LIBDEV_DIR = join(PROJROOT, LIBDEV_RELDIR)
LIBDEV_INC = join(LIBDEV_DIR, 'include')
env = Environment(CC = config.toolchain + 'gcc',
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', \
'-nostdinc', '-Wall', '-Werror', '-march=' + gcc_arch_flag],
LINKFLAGS = ['-nostdlib'],
ASFLAGS = ['-D__ASSEMBLY__'],
ENV = {'PATH' : os.environ['PATH']},
CPPPATH = ['include', LIBDEV_INC, join(PROJROOT,'include'), \
'include/sys-' + variant + '/arch-' + arch])
source = \
Glob('src/*.[cS]') + \
Glob('src/sys-' + variant + '/*.c') + \
Glob('src/sys-' + variant + '/arch-' + arch + '/*.c') + \
Glob('src/arch-' + arch + '/*.c') + \
Glob('src/arch-' + arch + '/*.S') + \
Glob('crt/sys-' + variant + '/arch-' + arch + '/*.[cS]')
objects = env.StaticObject(source)
library = env.StaticLibrary('c-' + variant, objects)

View File

@@ -181,7 +181,8 @@ int vsprintf(char *, const char *format, va_list arg);
int vsscanf(const char *s, const char *format, va_list arg);
/* 7.19.7 Character i/o functions */
int fgetc(FILE *);
char fgetc(FILE *);
char *fgetline(FILE *);
char *fgets(char *, int, FILE *);
int fputc(int, FILE *);
int fputs(const char *, FILE *);

View File

@@ -0,0 +1,92 @@
/*
* Australian Public Licence B (OZPLB)
*
* Version 1-0
*
* Copyright (c) 2004 National ICT Australia
*
* All rights reserved.
*
* Developed by: Embedded, Real-time and Operating Systems Program (ERTOS)
* National ICT Australia
* http://www.ertos.nicta.com.au
*
* Permission is granted by National ICT Australia, free of charge, to
* any person obtaining a copy of this software and any associated
* documentation files (the "Software") to deal with the Software without
* restriction, including (without limitation) the rights to use, copy,
* modify, adapt, merge, publish, distribute, communicate to the public,
* sublicense, and/or sell, lend or rent out copies of the Software, and
* to permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimers.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimers in the documentation and/or other materials provided
* with the distribution.
*
* * Neither the name of National ICT Australia, nor the names of its
* contributors, may be used to endorse or promote products derived
* from this Software without specific prior written permission.
*
* EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
* PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS", AND
* NATIONAL ICT AUSTRALIA AND ITS CONTRIBUTORS MAKE NO REPRESENTATIONS,
* WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS
* REGARDING THE CONTENTS OR ACCURACY OF THE SOFTWARE, OR OF TITLE,
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT,
* THE ABSENCE OF LATENT OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF
* ERRORS, WHETHER OR NOT DISCOVERABLE.
*
* TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
* NATIONAL ICT AUSTRALIA OR ITS CONTRIBUTORS BE LIABLE ON ANY LEGAL
* THEORY (INCLUDING, WITHOUT LIMITATION, IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHERWISE) FOR ANY CLAIM, LOSS, DAMAGES OR OTHER
* LIABILITY, INCLUDING (WITHOUT LIMITATION) LOSS OF PRODUCTION OR
* OPERATION TIME, LOSS, DAMAGE OR CORRUPTION OF DATA OR RECORDS; OR LOSS
* OF ANTICIPATED SAVINGS, OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR
* OTHER ECONOMIC LOSS; OR ANY SPECIAL, INCIDENTAL, INDIRECT,
* CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES, ARISING OUT OF OR IN
* CONNECTION WITH THIS LICENCE, THE SOFTWARE OR THE USE OF OR OTHER
* DEALINGS WITH THE SOFTWARE, EVEN IF NATIONAL ICT AUSTRALIA OR ITS
* CONTRIBUTORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH CLAIM, LOSS,
* DAMAGES OR OTHER LIABILITY.
*
* If applicable legislation implies representations, warranties, or
* conditions, or imposes obligations or liability on National ICT
* Australia or one of its contributors in respect of the Software that
* cannot be wholly or partly excluded, restricted or modified, the
* liability of National ICT Australia or the contributor is limited, to
* the full extent permitted by the applicable legislation, at its
* option, to:
* a. in the case of goods, any one or more of the following:
* i. the replacement of the goods or the supply of equivalent goods;
* ii. the repair of the goods;
* iii. the payment of the cost of replacing the goods or of acquiring
* equivalent goods;
* iv. the payment of the cost of having the goods repaired; or
* b. in the case of services:
* i. the supplying of the services again; or
* ii. the payment of the cost of having the services supplied again.
*
* The construction, validity and performance of this licence is governed
* by the laws in force in New South Wales, Australia.
*/
/*
Author: Ben Leslie
*/
typedef signed char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef long long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#define __PTR_SIZE 32

60
conts/libc/src/memcpy.S Normal file
View File

@@ -0,0 +1,60 @@
/*
* Copyright 2010 B Labs.Ltd.
*
* Author: Prem Mallappa <prem.mallappa@b-labs.co.uk>
*
* Description: Optimized memcpy for ARM
*
*/
#include INC_ARCH(asm.h)
/*
void*
memcpy(void *dst, const void *src, register uint len)
*/
BEGIN_PROC(memcpy)
push {r0, r4-r11, lr}
loop32:
cmp r2, #32
blt loop16
ldmia r1!, {r4 - r11}
stmia r0!, {r4 - r11}
sub r2, r2, #32
b loop32
loop16:
cmp r2, #16
blt loop8
ldmia r1!, {r4 - r7}
stmia r0!, {r4 - r7}
sub r2, r2, #16
b loop16
loop8:
cmp r2, #8
blt loop4
ldmia r1!, {r4, r5}
stmia r0!, {r4, r5}
sub r2, r2, #8
b loop8
loop4:
cmp r2, #4
blt end
ldmia r1!, {r4}
stmia r0!, {r4}
sub r2, r2, #4
b loop4
end:
last:
teq r2, #0
ldrgtb r4, [r1]
strneb r4, [r0] // V7 supports strneb <rt>, [<rb>, +/-<index>] !, with write back
lsrne r4, r4, #8
subne r2, r2, #1 // Can be reduced to 1 LDR, but has a catch if it is end of memory
addne r0, r0, #1 // we dont want to fetch 1 byte extra to end up in abort
addne r1, r1, #1 // so, playing safe, worst case 3 LDRs
bne last
1:
pop {r0, r4 - r11, pc}
END_PROC(_memcpy)

68
conts/libc/src/memset.S Normal file
View File

@@ -0,0 +1,68 @@
/*
* Copyright 2010 (C) B Labs.
* Author: Prem Mallappa <prem.mallappa@b-labs.co.uk>
* Description: Optimized memset for ARM
*/
#include INC_ARCH(asm.h)
/*
void *
memset(void *dst, int c, int len)
*/
BEGIN_PROC(memset)
stmfd sp!, {r4 - r11, lr}
and r1, r1, #255 /* c &= 0xff */
orr r1, r1, lsl #8 /* c |= c<<8 */
orr r1, r1, lsl #16 /* c |= c<<16 */
mov r4, r1
cmp r2, #8
blt 4f
movge r5, r4
cmpge r2, #16
blt 8f
movge r6, r4
movge r7, r4
cmpge r2, #32
blt 16f
movge r8, r4
movge r9, r4
movge r10, r4
movge r11, r4
32:
cmp r2, #32
blt 16f
stmia r0!, {r4 - r11}
sub r2, r2, #32
b 32b
16:
cmp r2, #16
blt 8f
stmia r0!, {r4 - r7}
sub r2, r2, #16
b 16b
8:
cmp r2, #8
blt 4f
stmia r0!, {r4, r5}
sub r2, r2, #8
b 8b
4:
cmp r2, #4
blt end
stmia r0!, {r4}
sub r2, r2, #4
b 4b
end:
teq r2, #0
strneb r4, [r0, #0]
subne r2, r2, #1
addne r0, r0, #1
bne end
ldmfd sp!, {r4 - r11, pc}
END_PROC(_memset)

View File

@@ -2,19 +2,12 @@
* Ties up platform's uart driver functions with printf
*
* Copyright (C) 2009 B Labs Ltd.
*
*/
#include <stdio.h>
#include <pl011_uart.h>
extern struct pl011_uart uart;
#include <libdev/uart.h>
int __fputc(int c, FILE *stream)
{
int res;
do {
res = pl011_tx_char(uart.base, c);
} while( res < 0);
return(0);
uart_tx_char(uart_print_base, c);
return 0;
}

View File

@@ -0,0 +1,31 @@
/*
* Library calls for uart rx.
*
* Copyright (C) 2009 B Labs Ltd.
*
*/
#include <stdio.h>
#include <libdev/uart.h>
char fgetc(FILE * file)
{
return uart_rx_char(uart_print_base);
}
#define MAX_LINE_LEN 256
char data[MAX_LINE_LEN];
char *fgetline(FILE * file)
{
int index = 0;
/*
* Line will end if,
* 1. We have recieved 256 chars or
* 2. we recieved EOL: '\n' followed by '\r'
*/
while((data[index] != '\n' && ((data[index++] = fgetc(file)) != '\r')) ||
index != MAX_LINE_LEN);
return data;
}

View File

@@ -15,29 +15,32 @@ sys.path.append(PROJRELROOT)
from config.configuration import *
from config.projpaths import *
Import('env', 'arch', 'platform', 'type')
Import('env', 'platform', 'type')
variant = type
# Path for uart files
LIBDEV_UART_PATH = join(PROJROOT, 'conts/libdev/uart')
# To include setbit/clrbit functions
LIBL4_RELDIR = 'conts/libl4'
LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR)
LIBL4_INC = join(LIBL4_DIR, 'include')
# Path for timer files
LIBDEV_TIEMR_PATH = join(PROJROOT, 'conts/libdev/timer/sp804')
# Path for clcd files
LIBDEV_CLCD_PATH = join(PROJROOT, 'conts/libdev/clcd/pl110')
LIBC_RELDIR = 'conts/libc'
LIBC_DIR = join(PROJROOT, LIBC_RELDIR)
LIBC_INC = join(LIBC_DIR, 'include')
e = env.Clone()
e.Append(CPPPATH = [LIBDEV_UART_PATH + '/include', LIBDEV_TIEMR_PATH + '/include',
LIBDEV_CLCD_PATH + '/include',],
CCFLAGS = ['-nostdinc', '-DVARIANT_' + variant.upper(),
'-DPLATFORM_' + platform.upper()])
e.Append(CPPPATH = ['#conts/libdev/include', LIBC_INC, LIBL4_INC],
CCFLAGS = ['-DVARIANT_' + variant.upper()])
source = Glob('uart/src' + '/*.c') + \
Glob('timer/sp804/src' + '/*.c') + \
Glob('clcd/pl110/src' + '/*.c')
objects = []
objects += SConscript('uart/pl011/SConscript', duplicate=0, \
exports = {'platform' : platform, 'env' : e})
objects += SConscript('timer/sp804/SConscript', duplicate=0, \
exports = {'platform' : platform, 'env' : e})
objects += SConscript('uart/omap/SConscript', duplicate=0, \
exports = {'platform' : platform, 'env' : e})
objects += SConscript('timer/omap/SConscript', duplicate=0, \
exports = {'platform' : platform, 'env' : e})
objects = e.StaticObject(source)
library = e.StaticLibrary('libdev-' + variant, objects)
Return('library')

51
conts/libdev/SConstruct Normal file
View File

@@ -0,0 +1,51 @@
# -*- mode: python; coding: utf-8; -*-
#
# Codezero -- a microkernel for embedded systems.
#
# Copyright © 2009 B Labs Ltd
#
import os, sys
PROJRELROOT = '../..'
sys.path.append(PROJRELROOT)
from config.projpaths import *
from config.configuration import *
config = configuration_retrieve()
gcc_arch_flag = config.gcc_arch_flag
platform = config.platform
# We assume we are compiling for userspace.
# variant can be specified from cmdline using
# scons variant=xxx
variant = ARGUMENTS.get('variant', 'userspace')
print '\nCompiling for variant: ' + variant + '\n'
# To include setbit/clrbit functions
LIBL4_RELDIR = 'conts/libl4'
LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR)
LIBL4_INC = join(LIBL4_DIR, 'include')
LIBC_RELDIR = 'conts/libc'
LIBC_DIR = join(PROJROOT, LIBC_RELDIR)
LIBC_INC = join(LIBC_DIR, 'include')
env = Environment(CC = config.toolchain + 'gcc',
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', \
'-nostdinc', '-Wall', '-DVARIANT_' + variant.upper(), \
'-march=' + gcc_arch_flag, '-Werror'],
LINKFLAGS = ['-nostdlib'],
ASFLAGS = ['-D__ASSEMBLY__'],
ENV = {'PATH' : os.environ['PATH']},
CPPPATH = ['#include', LIBC_INC, LIBL4_INC, join(PROJROOT,'include')])
objects = []
objects += SConscript('uart/pl011/SConscript', duplicate=0, \
exports = {'platform' : platform, 'env' : env})
objects += SConscript('timer/sp804/SConscript', duplicate=0, \
exports = {'platform' : platform, 'env' : env})
library = env.StaticLibrary('libdev-' + variant, objects)

View File

@@ -0,0 +1,12 @@
/*
* IO functions/macros.
*
* Copyright (C) 2007 Bahadir Balban
*/
#ifndef __LIBDEV_IO_H__
#define __LIBDEV_IO_H__
#define read(address) *((volatile unsigned int *)(address))
#define write(val, address) *((volatile unsigned int *)(address)) = val
#endif /* __LIBDEV_IO_H__ */

View File

@@ -0,0 +1,23 @@
/*
* Generic timer library API
*
* Copyright (C) 2010 B Labs Ltd.
*
* Author: Bahadir Balban
*/
#ifndef __LIBDEV_TIMER_H__
#define __LIBDEV_TIMER_H__
/*
* Simple API for the primary timer
* for userspace
*/
void timer_start(unsigned long timer_base);
void timer_load(u32 val, unsigned long timer_base);
u32 timer_read(unsigned long timer_base);
void timer_stop(unsigned long timer_base);
void timer_init_oneshot(unsigned long timer_base);
void timer_init_periodic(unsigned long timer_base);
void timer_init(unsigned long timer_base);
#endif /* __LIBDEV_TIMER_H__ */

View File

@@ -0,0 +1,21 @@
/*
* Generic uart API
*
* Copyright (C) 2010 B Labs Ltd.
*
* Author: Bahadir Balban
*/
#ifndef __LIBDEV_UART_H__
#define __LIBDEV_UART_H__
void uart_tx_char(unsigned long uart_base, char c);
char uart_rx_char(unsigned long uart_base);
void uart_set_baudrate(unsigned long uart_base, unsigned int val);
void uart_init(unsigned long base);
/*
* Base of primary uart used for printf
*/
extern unsigned long uart_print_base;
#endif /* __LIBDEV_UART_H__ */

View File

@@ -0,0 +1,15 @@
Import('env', 'platform')
#Platforms using omap_uart
plat_list = 'beagle'
# The set of source files associated with this SConscript file.
src_local = []
#for plat_supported in plat_list:
#if plat_supported == platform:
if plat_list == platform:
src_local += ['timer.c']
obj = env.StaticObject(src_local)
Return('obj')

View File

@@ -0,0 +1,97 @@
/*
* omap GP timer driver honoring generic
* timer library API
*
* Copyright (C) 2010 B Labs Ltd.
*
* Author: Bahadir Balban
*/
#include <libdev/io.h>
#include <l4lib/types.h>
#include "timer.h"
#define OMAP_TIMER_MAT_IT_FLAG (1 << 0)
#define OMAP_TIMER_OVR_IT_FLAG (1 << 1)
#define OMAP_TIMER_TCAR_IT_FLAG (1 << 2)
u32 timer_periodic_intr_status(unsigned long timer_base)
{
volatile u32 reg = read(timer_base + OMAP_TIMER_TISR);
return (reg & OMAP_TIMER_OVR_IT_FLAG);
}
#define OMAP_TIMER_SOFT_RESET (1 << 1)
void timer_reset(unsigned long timer_base)
{
/* Reset Timer */
write(OMAP_TIMER_SOFT_RESET, timer_base + OMAP_TIMER_TIOCP);
/* Wait for reset completion */
while (!read(timer_base + OMAP_TIMER_TSTAT));
}
void timer_load(unsigned long timer_base, u32 value)
{
write(value, timer_base + OMAP_TIMER_TLDR);
write(value, timer_base + OMAP_TIMER_TCRR);
}
u32 timer_read(unsigned long timer_base)
{
return read(timer_base + OMAP_TIMER_TCRR);
}
#define OMAP_TIMER_START (1 << 0)
void timer_start(unsigned long timer_base)
{
volatile u32 reg = read(timer_base + OMAP_TIMER_TCLR);
reg |= OMAP_TIMER_START;
write(reg, timer_base + OMAP_TIMER_TCLR);
}
void timer_stop(unsigned long timer_base)
{
volatile u32 reg = read(timer_base + OMAP_TIMER_TCLR);
reg &= (~OMAP_TIMER_START);
write(reg, timer_base + OMAP_TIMER_TCLR);
}
void timer_init_periodic(unsigned long timer_base)
{
volatile u32 reg;
/* Reset the timer */
timer_reset(timer_base);
/* Set timer to autoreload mode */
reg = read(timer_base + OMAP_TIMER_TCLR);
reg |= (1 << OMAP_TIMER_MODE_AUTORELAOD);
write(reg, timer_base + OMAP_TIMER_TCLR);
/*
* Beagle Board RevC manual:
* overflow period = (0xffffffff - TLDR + 1)*PS*(1/TIMER_FCLK)
* where,
* PS: Prescaler divisor (we are not using this)
*
* Beagle board manual says, 26MHz oscillator present on board.
* U-Boot divides the sys_clock by 2 if sys_clk is >19MHz,
* so,we have sys_clk frequency = 13MHz
*
* TIMER_FCLK = 13MHz
* So, for 1ms period, TLDR = 0xffffcd38
*
*/
timer_load(timer_base, 0xffffcd38);
/* Clear pending Interrupts, if any */
write(7, timer_base + OMAP_TIMER_TISR);
/* Enable inteerupts */
write((1 << OMAP_TIMER_INTR_OVERFLOW), timer_base + OMAP_TIMER_TIER);
}
void timer_init(unsigned long timer_base)
{
timer_init_periodic(timer_base);
}

View File

@@ -0,0 +1,51 @@
/*
* OMAP GP Timer offsets
*
* Copyright (C) 2007 Bahadir Balban
*
*/
#ifndef __OMAP_GPTIMER_H__
#define __OMAP_GPTIMER_H__
/* Register offsets */
#define OMAP_TIMER_TIOCP 0x10
#define OMAP_TIMER_TSTAT 0x14
#define OMAP_TIMER_TISR 0x18
#define OMAP_TIMER_TIER 0x1C
#define OMAP_TIMER_TCLR 0x24
#define OMAP_TIMER_TCRR 0x28
#define OMAP_TIMER_TLDR 0x2C
#define OMAP_TIMER_TPIR 0x48
#define OMAP_TIMER_TNIR 0x4C
#define OMAP_TIMER_TCVR 0x50
/* Enable/Disable IRQ */
#define OMAP_TIMER_IRQENABLE 1
#define OMAP_TIMER_IRQDISABLE 0
/* Timer modes supported */
#define OMAP_TIMER_MODE_AUTORELAOD 1
#define OMAP_TIMER_MODE_COMPARE 6
#define OMAP_TIMER_MODE_CAPTURE 13
/* Interrupt types */
#define OMAP_TIMER_INTR_MATCH 0x0
#define OMAP_TIMER_INTR_OVERFLOW 0x1
#define OMAP_TIMER_INTR_CAPTURE 0x2
/* Clock source for timer */
#define OMAP_TIMER_CLKSRC_SYS_CLK 0x1
#define OMAP_TIMER_CLKSRC_32KHZ_CLK 0x0
u32 timer_periodic_intr_status(unsigned long timer_base);
void timer_start(unsigned long base);
void timer_set_mode(unsigned long base, int mode);
void timer_reset(unsigned long timer_base);
void timer_load(unsigned long timer_base, u32 value);
u32 timer_read(unsigned long timer_base);
void timer_start(unsigned long timer_base);
void timer_stop(unsigned long timer_base);
void timer_init_periodic(unsigned long timer_base);
void timer_init(unsigned long timer_base);
#endif /* __OMAP_GPTIMER_H__*/

View File

@@ -0,0 +1,14 @@
Import('env', 'platform')
#Platforms using sp804
plat_list = ('eb', 'pba8', 'pba9', 'pb11mpcore', 'pb926')
# The set of source files associated with this SConscript file.
src_local = []
for plat_supported in plat_list:
if plat_supported == platform:
src_local += Glob('*.c')
obj = env.StaticObject(src_local)
Return('obj')

View File

@@ -0,0 +1,65 @@
/*
* SP804 primecell driver honoring generic
* timer library API
*
* Copyright (C) 2010 B Labs Ltd.
*
* Author: Bahadir Balban
*/
#include <l4lib/types.h>
#include "timer.h"
/* Enable timer with its current configuration */
void timer_start(unsigned long timer_base)
{
volatile u32 reg = read(timer_base + SP804_CTRL);
reg |= SP804_ENABLE;
write(reg, timer_base + SP804_CTRL);
}
/* Load the timer with ticks value */
void timer_load(u32 loadval, unsigned long timer_base)
{
write(loadval, timer_base + SP804_LOAD);
}
u32 timer_read(unsigned long timer_base)
{
return read(timer_base + SP804_VALUE);
}
void timer_stop(unsigned long timer_base)
{
write(0, timer_base + SP804_CTRL);
}
void timer_init_periodic(unsigned long timer_base)
{
volatile u32 reg = read(timer_base + SP804_CTRL);
reg |= SP804_PERIODIC | SP804_32BIT | SP804_IRQEN;
write(reg, timer_base + SP804_CTRL);
/* 1 tick per usec, 1 irq per msec */
timer_load(1000, timer_base);
}
void timer_init_oneshot(unsigned long timer_base)
{
volatile u32 reg = read(timer_base + SP804_CTRL);
/* One shot, 32 bits, no irqs */
reg |= SP804_32BIT | SP804_ONESHOT;
write(reg, timer_base + SP804_CTRL);
}
void timer_init(unsigned long timer_base)
{
timer_stop(timer_base);
timer_init_periodic(timer_base);
}

View File

@@ -0,0 +1,63 @@
/*
* SP804 Primecell Timer offsets
*
* Copyright (C) 2007 Bahadir Balban
*
*/
#ifndef __SP804_TIMER_H__
#define __SP804_TIMER_H__
#include <libdev/io.h>
/* Register offsets */
#define SP804_LOAD 0x0
#define SP804_VALUE 0x4
#define SP804_CTRL 0x8
#define SP804_INTCLR 0xC
#define SP804_RIS 0x10
#define SP804_MIS 0x14
#define SP804_BGLOAD 0x18
#define SP804_ENABLE (1 << 7)
#define SP804_PERIODIC (1 << 6)
#define SP804_IRQEN (1 << 5)
#define SP804_32BIT (1 << 1)
#define SP804_ONESHOT (1 << 0)
/* Timer prescaling */
#define SP804_SCALE_SHIFT 2
#define SP804_SCALE_DIV16 1
#define SP804_SCALE_DIV256 2
/* Wrapping = 0, Oneshot = 1 */
#define SP804_ONESHOT (1 << 0)
static inline __attribute__ ((always_inline))
void sp804_load(unsigned long timer_base, u32 val)
{
write(val, timer_base + SP804_LOAD);
}
static inline __attribute__ ((always_inline))
void sp804_irq_clear(unsigned long timer_base)
{
write(1, timer_base + SP804_INTCLR);
}
static inline __attribute__ ((always_inline))
void sp804_enable(unsigned long timer_base)
{
volatile u32 reg = read(timer_base + SP804_CTRL);
write(reg | SP804_ENABLE, timer_base + SP804_CTRL);
}
void timer_start(unsigned long timer_base);
void timer_load(u32 loadval, unsigned long timer_base);
u32 timer_read(unsigned long timer_base);
void timer_stop(unsigned long timer_base);
void timer_init_periodic(unsigned long timer_base);
void timer_init_oneshot(unsigned long timer_base);
void timer_init(unsigned long timer_base);
#endif /* __SP804_TIMER_H__ */

View File

@@ -0,0 +1,15 @@
Import('env', 'platform')
#Platforms using omap_uart
plat_list = 'beagle'
# The set of source files associated with this SConscript file.
src_local = []
#for plat_supported in plat_list:
#if plat_supported == platform:
if plat_list == platform:
src_local += ['uart.c']
obj = env.StaticObject(src_local)
Return('obj')

View File

@@ -0,0 +1,115 @@
/*
* UART driver used by OMAP devices
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <libdev/uart.h>
#include <libdev/io.h>
#include "uart.h"
#define OMAP_UART_TXFE 0x20
void uart_tx_char(unsigned long uart_base, char c)
{
volatile u32 reg;
/* Check if there is space for tx */
do {
reg = read(uart_base + OMAP_UART_LSR);
} while(!(reg & OMAP_UART_TXFE));
write(c, uart_base + OMAP_UART_THR);
}
#define OMAP_UART_RXFNE 0x1
#define OMAP_UART_RX_FIFO_STATUS 0x8
char uart_rx_char(unsigned long uart_base)
{
volatile u32 reg;
/* Check if pending data is there */
do {
reg = read(uart_base + OMAP_UART_LSR);
} while(!(reg & OMAP_UART_RXFNE));
#if 0
/* Check if there is some error in recieve */
if(reg & OMAP_UART_RX_FIFO_STATUS)
return -1;
#endif
return (char)read(uart_base + OMAP_UART_RHR);
}
void uart_set_baudrate(unsigned long uart_base, u32 baudrate)
{
u32 clk_div;
/* 48Mhz clock fixed on beagleboard */
const u32 clkrate = 48000000;
/* If baud out of range, set default rate */
if(baudrate > 3686400 || baudrate < 300)
baudrate = 115200;
clk_div = clkrate/(16 * baudrate);
/* Set clockrate in DLH and DLL */
write((clk_div & 0xff), uart_base + OMAP_UART_DLL);
write(((clk_div >> 8) & 0xff ), uart_base + OMAP_UART_DLH);
}
void uart_init(unsigned long uart_base)
{
/* Disable UART */
uart_select_mode(uart_base, OMAP_UART_MODE_DEFAULT);
/* Disable interrupts */
uart_disable_interrupt(uart_base);
/* Change to config mode, to set baud divisor */
uart_set_link_control(uart_base, OMAP_UART_BANKED_MODE_CONFIG_A);
/* Set the baud rate */
uart_set_baudrate(uart_base, 115200);
/* Switch to operational mode */
uart_set_link_control(uart_base, OMAP_UART_BANKED_MODE_OPERATIONAL);
/* Set up the link- parity, data bits stop bits to 8N1 */
uart_disable_parity(uart_base);
uart_set_data_bits(uart_base, OMAP_UART_DATA_BITS_8);
uart_set_stop_bits(uart_base, OMAP_UART_STOP_BITS_1);
/* Disable Fifos */
uart_disable_fifo(uart_base);
/* Enable modem Rx/Tx */
uart_enable_tx(uart_base);
uart_enable_rx(uart_base);
/* Enable UART in 16x mode */
uart_select_mode(uart_base, OMAP_UART_MODE_UART16X);
}
unsigned long uart_print_base;
void platform_init(void)
{
uart_print_base = OMAP_UART_BASE;
/*
* We dont need to initialize uart here for variant-userspace,
* as this is the same uart as used by kernel and hence
* already initialized, we just need
* a uart struct instance with proper base address.
*
* But in case of baremetal like loader, no one has done
* initialization, so we need to do it.
*/
#if defined(VARIANT_BAREMETAL)
uart_init(uart_print_base);
#endif
}

View File

@@ -0,0 +1,195 @@
/*
* OMAP UART Generic driver implementation.
*
* Copyright (C) 2007 Bahadir Balban
*
* The particular intention of this code is that it has been carefully written
* as decoupled from os-specific code and in a verbose way such that it clearly
* demonstrates how the device operates, reducing the amount of time to be spent
* for understanding the operational model and implementing a driver from
* scratch. This is the very first to be such a driver so far, hopefully it will
* turn out to be useful.
*/
#ifndef __OMAP_UART_H__
#define __OMAP_UART_H__
#include <l4/config.h> /* To get PLATFORM */
#include <l4lib/types.h>
#if defined(VARIANT_USERSPACE)
/* FIXME: Take this value in agreement from kernel, or from kernel only */
#include <l4/macros.h>
#include INC_ARCH(io.h)
#define OMAP_UART_BASE USERSPACE_CONSOLE_VBASE
#endif
#if defined(VARIANT_BAREMETAL)
#if defined(CONFIG_PLATFORM_BEAGLE)
#define OMAP_UART_BASE 0x49020000
#endif
#endif
/* Register offsets */
#define OMAP_UART_DLL 0x00
#define OMAP_UART_THR 0x00
#define OMAP_UART_RHR 0x00
#define OMAP_UART_DLH 0x04
#define OMAP_UART_IER 0x04
#define OMAP_UART_FCR 0x08
#define OMAP_UART_MCR 0x10
#define OMAP_UART_LSR 0x14
#define OMAP_UART_MDR1 0x20
#define OMAP_UART_LCR 0x0C
/* Modes supported by OMAP UART/IRDA/CIR IP */
#define OMAP_UART_MODE_UART16X 0x0
#define OMAP_UART_MODE_SIR 0x1
#define OMAP_UART_MODE_UART16X_AUTO_BAUD 0x2
#define OMAP_UART_MODE_UART13X 0x3
#define OMAP_UART_MODE_MIR 0x4
#define OMAP_UART_MODE_FIR 0x5
#define OMAP_UART_MODE_CIR 0x6
#define OMAP_UART_MODE_DEFAULT 0x7 /* Disable */
/* Number of data bits for UART */
#define OMAP_UART_DATA_BITS_5 0x0
#define OMAP_UART_DATA_BITS_6 0x1
#define OMAP_UART_DATA_BITS_7 0x2
#define OMAP_UART_DATA_BITS_8 0x3
/* Stop bits to be used for UART data */
#define OMAP_UART_STOP_BITS_1 0x0
#define OMAP_UART_STOP_BITS_1_5 0x1
/* Banked Register modes- ConfigA, ConfigB, Operational */
#define OMAP_UART_BANKED_MODE_OPERATIONAL 0x00
#define OMAP_UART_BANKED_MODE_CONFIG_A 0x80
#define OMAP_UART_BANKED_MODE_CONFIG_B 0xBF
void uart_tx_char(unsigned long uart_base, char c);
char uart_rx_char(unsigned long uart_base);
void uart_set_baudrate(unsigned long uart_base, u32 baudrate);
void uart_init(unsigned long uart_base);
#define OMAP_UART_FIFO_ENABLE (1 << 0)
#define OMAP_UART_RX_FIFO_CLR (1 << 1)
#define OMAP_UART_TX_FIFO_CLR (1 << 2)
static inline void uart_enable_fifo(unsigned long uart_base)
{
volatile u32 reg = read(uart_base + OMAP_UART_FCR);
reg |= (OMAP_UART_FIFO_ENABLE | OMAP_UART_RX_FIFO_CLR |
OMAP_UART_TX_FIFO_CLR);
write(reg, uart_base + OMAP_UART_FCR);
}
static inline void uart_disable_fifo(unsigned long uart_base)
{
volatile u32 reg= read(uart_base + OMAP_UART_FCR);
reg &= (~OMAP_UART_FIFO_ENABLE | OMAP_UART_RX_FIFO_CLR |
OMAP_UART_TX_FIFO_CLR);
write(reg, uart_base + OMAP_UART_FCR);
}
#define OMAP_UART_TX_ENABLE (1 << 0)
static inline void uart_enable_tx(unsigned long uart_base)
{
volatile u32 reg = read(uart_base + OMAP_UART_MCR);
reg |= OMAP_UART_TX_ENABLE;
write(reg, uart_base + OMAP_UART_MCR);
}
static inline void uart_disable_tx(unsigned long uart_base)
{
volatile u32 reg = read(uart_base + OMAP_UART_MCR);
reg &= ~OMAP_UART_TX_ENABLE;
write(reg, uart_base + OMAP_UART_MCR);
}
#define OMAP_UART_RX_ENABLE (1 << 1)
static inline void uart_enable_rx(unsigned long uart_base)
{
volatile u32 reg = read(uart_base + OMAP_UART_MCR);
reg |= OMAP_UART_RX_ENABLE;
write(reg, uart_base + OMAP_UART_MCR);
}
static inline void uart_disable_rx(unsigned long uart_base)
{
volatile u32 reg = read(uart_base + OMAP_UART_MCR);
reg &= ~OMAP_UART_RX_ENABLE;
write(reg, uart_base + OMAP_UART_MCR);
}
#define OMAP_UART_STOP_BITS_MASK (1 << 2)
static inline void uart_set_stop_bits(unsigned long uart_base, int bits)
{
volatile u32 reg = read(uart_base + OMAP_UART_LCR);
reg &= ~OMAP_UART_STOP_BITS_MASK;
reg |= (bits << 2);
write(reg, uart_base + OMAP_UART_LCR);
}
#define OMAP_UART_DATA_BITS_MASK (0x3)
static inline void uart_set_data_bits(unsigned long uart_base, int bits)
{
volatile u32 reg = read(uart_base + OMAP_UART_LCR);
reg &= ~OMAP_UART_DATA_BITS_MASK;
reg |= bits;
write(reg, uart_base + OMAP_UART_LCR);
}
#define OMAP_UART_PARITY_ENABLE (1 << 3)
static inline void uart_enable_parity(unsigned long uart_base)
{
volatile u32 reg = read(uart_base + OMAP_UART_LCR);
reg |= OMAP_UART_PARITY_ENABLE;
write(reg, uart_base + OMAP_UART_LCR);
}
static inline void uart_disable_parity(unsigned long uart_base)
{
volatile u32 reg = read(uart_base + OMAP_UART_LCR);
reg &= ~OMAP_UART_PARITY_ENABLE;
write(reg, uart_base + OMAP_UART_LCR);
}
#define OMAP_UART_PARITY_EVEN (1 << 4)
static inline void uart_set_even_parity(unsigned long uart_base)
{
volatile u32 reg = read(uart_base + OMAP_UART_LCR);
reg |= OMAP_UART_PARITY_EVEN;
write(reg, uart_base + OMAP_UART_LCR);
}
static inline void uart_set_odd_parity(unsigned long uart_base)
{
volatile u32 reg = read(uart_base + OMAP_UART_LCR);
reg &= ~OMAP_UART_PARITY_EVEN;
write(reg, uart_base + OMAP_UART_LCR);
}
static inline void uart_select_mode(unsigned long uart_base, int mode)
{
write(mode, uart_base + OMAP_UART_MDR1);
}
#define OMAP_UART_INTR_EN 1
static inline void uart_enable_interrupt(unsigned long uart_base)
{
write(OMAP_UART_INTR_EN, uart_base + OMAP_UART_IER);
}
static inline void uart_disable_interrupt(unsigned long uart_base)
{
write((~OMAP_UART_INTR_EN), uart_base + OMAP_UART_IER);
}
static inline void uart_set_link_control(unsigned long uart_base, int mode)
{
write(mode, uart_base + OMAP_UART_LCR);
}
#endif /* __OMAP_UART_H__ */

View File

@@ -0,0 +1,14 @@
Import('env', 'platform')
#Platforms using pl011
plat_list = ('eb', 'pba8', 'pba9', 'pb11mpcore', 'pb926')
# The set of source files associated with this SConscript file.
src_local = []
for plat_supported in plat_list:
if plat_supported == platform:
src_local += Glob('*.c')
obj = env.StaticObject(src_local)
Return('obj')

View File

@@ -0,0 +1,127 @@
/*
* PL011 UART driver
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <libdev/uart.h>
#include <libdev/io.h>
#include "uart.h"
/* Error status bits in receive status register */
#define PL011_FE (1 << 0)
#define PL011_PE (1 << 1)
#define PL011_BE (1 << 2)
#define PL011_OE (1 << 3)
/* Status bits in flag register */
#define PL011_TXFE (1 << 7)
#define PL011_RXFF (1 << 6)
#define PL011_TXFF (1 << 5)
#define PL011_RXFE (1 << 4)
#define PL011_BUSY (1 << 3)
#define PL011_DCD (1 << 2)
#define PL011_DSR (1 << 1)
#define PL011_CTS (1 << 0)
void uart_tx_char(unsigned long base, char c)
{
unsigned int val = 0;
do {
val = read((base + PL011_UARTFR));
} while (val & PL011_TXFF); /* TX FIFO FULL */
write(c, (base + PL011_UARTDR));
}
char uart_rx_char(unsigned long base)
{
unsigned int val = 0;
do {
val = read(base + PL011_UARTFR);
} while (val & PL011_RXFE); /* RX FIFO Empty */
return (char)read((base + PL011_UARTDR));
}
/*
* Sets the baud rate in kbps. It is recommended to use
* standard rates such as: 1200, 2400, 3600, 4800, 7200,
* 9600, 14400, 19200, 28800, 38400, 57600 76800, 115200.
*/
void pl011_set_baudrate(unsigned long base, unsigned int baud,
unsigned int clkrate)
{
const unsigned int uartclk = 24000000; /* 24Mhz clock fixed on pb926 */
unsigned int val = 0, ipart = 0, fpart = 0;
/* Use default pb926 rate if no rate is supplied */
if (clkrate == 0)
clkrate = uartclk;
if (baud > 115200 || baud < 1200)
baud = 38400; /* Default rate. */
/* 24000000 / (38400 * 16) */
ipart = 39;
write(ipart, base + PL011_UARTIBRD);
write(fpart, base + PL011_UARTFBRD);
/*
* For the IBAUD and FBAUD to update, we need to
* write to UARTLCR_H because the 3 registers are
* actually part of a single register in hardware
* which only updates by a write to UARTLCR_H
*/
val = read(base + PL011_UARTLCR_H);
write(val, base + PL011_UARTLCR_H);
}
void uart_init(unsigned long uart_base)
{
/* Initialise data register for 8 bit data read/writes */
pl011_set_word_width(uart_base, 8);
/*
* Fifos are disabled because by default it is assumed the port
* will be used as a user terminal, and in that case the typed
* characters will only show up when fifos are flushed, rather than
* when each character is typed. We avoid this by not using fifos.
*/
pl011_disable_fifos(uart_base);
/* Set default baud rate of 38400 */
pl011_set_baudrate(uart_base, 38400, 24000000);
/* Set default settings of 1 stop bit, no parity, no hw flow ctrl */
pl011_set_stopbits(uart_base, 1);
pl011_parity_disable(uart_base);
/* Enable rx, tx, and uart chip */
pl011_tx_enable(uart_base);
pl011_rx_enable(uart_base);
pl011_uart_enable(uart_base);
}
unsigned long uart_print_base;
void platform_init(void)
{
uart_print_base = PL011_BASE;
/*
* We dont need to initialize uart here for variant-userspace,
* as this is the same uart as used by kernel and hence
* already initialized, we just need
* a uart struct instance with proper base address.
*
* But in case of baremetal like loader, no one has done
* initialization, so we need to do it.
*/
#if defined(VARIANT_BAREMETAL)
uart_init(uart_print_base);
#endif
}

View File

@@ -0,0 +1,252 @@
/*
* PL011 UART Generic driver implementation.
* Copyright Bahadir Balban (C) 2009
*/
#ifndef __PL011_H__
#define __PL011_H__
#include <l4/config.h> /* To get PLATFORM */
#include <libdev/io.h>
#if defined(VARIANT_USERSPACE)
/* FIXME: Take this value in agreement from kernel, or from kernel only */
#include <l4/macros.h>
#include INC_ARCH(io.h)
#define PL011_BASE USERSPACE_CONSOLE_VBASE
#endif
#if defined(VARIANT_BAREMETAL)
#if defined(CONFIG_PLATFORM_PB926)
#define PL011_BASE 0x101F1000
#elif defined(CONFIG_PLATFORM_EB) || defined(CONFIG_PLATFORM_PB11MPCORE)
#define PL011_BASE 0x10009000
#elif defined(CONFIG_PLATFORM_PBA9) || defined(CONFIG_PLATFORM_PBA8)
#define PL011_BASE 0x10009000
#endif
#endif
/* Register offsets */
#define PL011_UARTDR 0x00
#define PL011_UARTRSR 0x04
#define PL011_UARTECR 0x04
#define PL011_UARTFR 0x18
#define PL011_UARTILPR 0x20
#define PL011_UARTIBRD 0x24
#define PL011_UARTFBRD 0x28
#define PL011_UARTLCR_H 0x2C
#define PL011_UARTCR 0x30
#define PL011_UARTIFLS 0x34
#define PL011_UARTIMSC 0x38
#define PL011_UARTRIS 0x3C
#define PL011_UARTMIS 0x40
#define PL011_UARTICR 0x44
#define PL011_UARTDMACR 0x48
/* IRQ bits for each uart irq event */
#define PL011_RXIRQ (1 << 4)
#define PL011_TXIRQ (1 << 5)
#define PL011_RXTIMEOUTIRQ (1 << 6)
#define PL011_FEIRQ (1 << 7)
#define PL011_PEIRQ (1 << 8)
#define PL011_BEIRQ (1 << 9)
#define PL011_OEIRQ (1 << 10)
void pl011_set_baudrate(unsigned long base, unsigned int baud,
unsigned int clkrate);
#define PL011_UARTEN (1 << 0)
static inline void pl011_uart_enable(unsigned long base)
{
unsigned int val = 0;
val = read((base + PL011_UARTCR));
val |= PL011_UARTEN;
write(val, (base + PL011_UARTCR));
return;
}
static inline void pl011_uart_disable(unsigned long base)
{
unsigned int val = 0;
val = read((base + PL011_UARTCR));
val &= ~PL011_UARTEN;
write(val, (base + PL011_UARTCR));
return;
}
#define PL011_TXE (1 << 8)
static inline void pl011_tx_enable(unsigned long base)
{
unsigned int val = 0;
val = read((base + PL011_UARTCR));
val |= PL011_TXE;
write(val, (base + PL011_UARTCR));
return;
}
static inline void pl011_tx_disable(unsigned long base)
{
unsigned int val = 0;
val =read((base + PL011_UARTCR));
val &= ~PL011_TXE;
write(val, (base + PL011_UARTCR));
return;
}
#define PL011_RXE (1 << 9)
static inline void pl011_rx_enable(unsigned long base)
{
unsigned int val = 0;
val = read((base + PL011_UARTCR));
val |= PL011_RXE;
write(val, (base + PL011_UARTCR));
return;
}
static inline void pl011_rx_disable(unsigned long base)
{
unsigned int val = 0;
val = read((base + PL011_UARTCR));
val &= ~PL011_RXE;
write(val, (base + PL011_UARTCR));
return;
}
#define PL011_TWO_STOPBITS_SELECT (1 << 3)
static inline void pl011_set_stopbits(unsigned long base, int stopbits)
{
unsigned int val = 0;
val = read((base + PL011_UARTLCR_H));
if(stopbits == 2) { /* Set to two bits */
val |= PL011_TWO_STOPBITS_SELECT;
} else { /* Default is 1 */
val &= ~PL011_TWO_STOPBITS_SELECT;
}
write(val, (base + PL011_UARTLCR_H));
return;
}
#define PL011_PARITY_ENABLE (1 << 1)
static inline void pl011_parity_enable(unsigned long base)
{
unsigned int val = 0;
val = read((base +PL011_UARTLCR_H));
val |= PL011_PARITY_ENABLE;
write(val, (base + PL011_UARTLCR_H));
return;
}
static inline void pl011_parity_disable(unsigned long base)
{
unsigned int val = 0;
val = read((base + PL011_UARTLCR_H));
val &= ~PL011_PARITY_ENABLE;
write(val, (base + PL011_UARTLCR_H));
return;
}
#define PL011_PARITY_EVEN (1 << 2)
static inline void pl011_set_parity_even(unsigned long base)
{
unsigned int val = 0;
val = read((base + PL011_UARTLCR_H));
val |= PL011_PARITY_EVEN;
write(val, (base + PL011_UARTLCR_H));
return;
}
static inline void pl011_set_parity_odd(unsigned long base)
{
unsigned int val = 0;
val = read((base + PL011_UARTLCR_H));
val &= ~PL011_PARITY_EVEN;
write(val, (base + PL011_UARTLCR_H));
return;
}
#define PL011_ENABLE_FIFOS (1 << 4)
static inline void pl011_enable_fifos(unsigned long base)
{
unsigned int val = 0;
val = read((base + PL011_UARTLCR_H));
val |= PL011_ENABLE_FIFOS;
write(val, (base + PL011_UARTLCR_H));
return;
}
static inline void pl011_disable_fifos(unsigned long base)
{
unsigned int val = 0;
val = read((base + PL011_UARTLCR_H));
val &= ~PL011_ENABLE_FIFOS;
write(val, (base + PL011_UARTLCR_H));
return;
}
/* Sets the transfer word width for the data register. */
static inline void pl011_set_word_width(unsigned long base, int size)
{
unsigned int val = 0;
if(size < 5 || size > 8) /* Default is 8 */
size = 8;
/* Clear size field */
val = read((base + PL011_UARTLCR_H));
val &= ~(0x3 << 5);
write(val, (base + PL011_UARTLCR_H));
/*
* The formula is to write 5 less of size given:
* 11 = 8 bits
* 10 = 7 bits
* 01 = 6 bits
* 00 = 5 bits
*/
val = read((base + PL011_UARTLCR_H));
val |= (size - 5) << 5;
write(val, (base + PL011_UARTLCR_H));
return;
}
/*
* Defines at which level of fifo fullness an irq will be generated.
* @xfer: tx fifo = 0, rx fifo = 1
* @level: Generate irq if:
* 0 rxfifo >= 1/8 full txfifo <= 1/8 full
* 1 rxfifo >= 1/4 full txfifo <= 1/4 full
* 2 rxfifo >= 1/2 full txfifo <= 1/2 full
* 3 rxfifo >= 3/4 full txfifo <= 3/4 full
* 4 rxfifo >= 7/8 full txfifo <= 7/8 full
* 5-7 reserved reserved
*/
static inline void pl011_set_irq_fifolevel(unsigned long base, \
unsigned int xfer, unsigned int level)
{
if(xfer != 1 && xfer != 0) /* Invalid fifo */
return;
if(level > 4) /* Invalid level */
return;
write(level << (xfer * 3), (base + PL011_UARTIFLS));
return;
}
#endif /* __PL011__UART__ */

View File

@@ -26,36 +26,36 @@ sys.path.append(PROJRELROOT)
from config.projpaths import *
from configure import *
Import('arch')
Import('env', 'arch', 'subarch')
config = configuration_retrieve()
LIBMEM_RELDIR = 'conts/libmem'
LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR)
env = Environment(CC = config.user_toolchain + 'gcc',
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')])
e = env.Clone()
e.Append(CPPPATH = ['include', 'include/l4lib/arch',
LIBMEM_DIR],
CPPFLAGS = ' -include l4lib/macros.h ')
env.Append(CPPPATH = [LIBMEM_DIR])
#Do we need to remove CPPFLAGS coming from top level env?
def create_symlinks(arch):
print os.getcwd()
prefix = 'conts/libl4/include/l4lib'
symlink = join(prefix, 'arch')
reallink = join(prefix, 'arch-' + arch)
# Use os.path.walk(dirname, glob_by_walk, ['*.[cS]', filelist])
# To collect all files in the tree.
if not os.path.exists(symlink):
cmd = "ln -s %s %s" % (reallink, symlink)
print cmd
os.system(cmd)
def glob_by_walk(arg, dirname, names):
ext, imglist = arg
files = glob.glob(join(dirname, ext))
imglist.extend(files)
#create_symlinks(arch)
objects = env.StaticObject(Glob('src/*.c') + Glob('src/thread/*.c') + Glob('src/' + arch + '/*.[cS]') + Glob('src/capability/*c'))
library = env.StaticLibrary('l4', objects)
objects = e.StaticObject(Glob('src/*.c') + \
Glob('src/lib/*.c') + \
Glob('src/lib/cap/*.c')) + \
Glob('src/lib/thread/*.c') + \
Glob('src/arch/' + arch + '/exregs.c') + \
Glob('src/arch/' + arch + '/*.S') + \
Glob('src/arch/' + arch + '/' + subarch + '/*.[cS]')
library = e.StaticLibrary('l4', objects)
Return('library')

View File

@@ -14,23 +14,35 @@ from config.projpaths import *
from config.configuration import *
config = configuration_retrieve()
gcc_arch_flag = config.gcc_arch_flag
arch = config.arch
subarch = config.subarch
LIBMEM_RELDIR = 'conts/libmem'
LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR)
env = Environment(CC = config.user_toolchain + 'gcc',
CCFLAGS = ['-std=gnu99', '-g', '-nostdlib', '-ffreestanding', '-Werror'],
LIBC_RELDIR = 'conts/libc'
LIBC_DIR = join(PROJROOT, LIBC_RELDIR)
LIBC_INC = join(LIBC_DIR, 'include')
env = Environment(CC = config.toolchain + 'gcc',
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', \
'-nostdinc', '-Wall', '-Werror', '-march=' + gcc_arch_flag],
LINKFLAGS = ['-nostdlib'],
ASFLAGS = ['-D__ASSEMBLY__'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc',
CPPPATH = ['#include', '#include/l4lib/arch', join(PROJROOT,'include'), \
LIBMEM_DIR])
CPPPATH = ['include', 'include/l4lib/arch', LIBC_INC, \
join(PROJROOT,'include'), LIBMEM_DIR],
CPPFLAGS = ' -include l4lib/macros.h ')
objects = env.StaticObject(Glob('src/*.c') + \
Glob('src/lib/*.c') + \
Glob('src/arch/' + arch + '/exregs.c') + \
Glob('src/arch/' + arch + '/*.[cS]') + \
Glob('src/arch/' + arch + '/' + subarch + '/*.[cS]') + \
Glob('src/lib/cap/*.c')) + \
Glob('src/lib/thread/*.c')
# TODO: There are errors in this code that -Werror gives problems with.
objects = env.StaticObject(Glob('src/*.c') + Glob('src/thread/*.c') + Glob('src/' + arch + '/*.[cS]'))
library = env.StaticLibrary('l4', objects)
#Return('library')

View File

@@ -0,0 +1,15 @@
#ifndef __ARM_ASM_H__
#define __ARM_ASM_H__
#define BEGIN_PROC(name) \
.global name; \
.type name,function; \
.align; \
name:
#define END_PROC(name) \
.fend_##name: \
.size name,.fend_##name - name;
#endif /* __ARM_ASM_H__ */

View File

@@ -0,0 +1,11 @@
#ifndef __L4LIB_ARCH_IRQ_H__
#define __L4LIB_ARCH_IRQ_H__
/*
* Destructive atomic-read.
*
* Write 0 to byte at @location as its contents are read back.
*/
char l4_atomic_dest_readb(void *location);
#endif

View File

@@ -0,0 +1,95 @@
/*
* System call prototypes.
*
* Copyright (C) 2007 Bahadir Balban
*/
#ifndef __ARM_SYSCALLS_H__
#define __ARM_SYSCALLS_H__
#include L4LIB_INC_ARCH(types.h)
#include L4LIB_INC_ARCH(utcb.h)
#include <l4/generic/space.h>
#include <l4/api/space.h>
#include <l4/api/kip.h>
#include <l4/api/ipc.h>
#include <l4/api/thread.h>
struct task_ids {
l4id_t tid;
l4id_t spid;
l4id_t tgid;
};
static inline void *
l4_kernel_interface(unsigned int *api_version, unsigned int *api_flags,
unsigned int *kernel_id)
{
return (void *)L4_KIP_ADDRESS;
}
typedef unsigned int (*__l4_thread_switch_t)(u32);
extern __l4_thread_switch_t __l4_thread_switch;
unsigned int l4_thread_switch (u32 dest);
typedef int (*__l4_getid_t)(struct task_ids *ids);
extern __l4_getid_t __l4_getid;
int l4_getid(struct task_ids *ids);
typedef int (*__l4_ipc_t)(l4id_t to, l4id_t from, u32 flags);
extern __l4_ipc_t __l4_ipc;
int l4_ipc(l4id_t to, l4id_t from, u32 flags);
typedef int (*__l4_capability_control_t)(unsigned int req, unsigned int flags, void *buf);
extern __l4_capability_control_t __l4_capability_control;
int l4_capability_control(unsigned int req, unsigned int flags, void *buf);
typedef int (*__l4_map_t)(void *phys, void *virt,
u32 npages, u32 flags, l4id_t tid);
extern __l4_map_t __l4_map;
int l4_map(void *p, void *v, u32 npages, u32 flags, l4id_t tid);
typedef int (*__l4_unmap_t)(void *virt, unsigned long npages, l4id_t tid);
extern __l4_unmap_t __l4_unmap;
int l4_unmap(void *virtual, unsigned long numpages, l4id_t tid);
typedef int (*__l4_thread_control_t)(unsigned int action, struct task_ids *ids);
extern __l4_thread_control_t __l4_thread_control;
int l4_thread_control(unsigned int action, struct task_ids *ids);
typedef int (*__l4_irq_control_t)(unsigned int req, unsigned int flags, l4id_t id);
extern __l4_irq_control_t __l4_irq_control;
int l4_irq_control(unsigned int req, unsigned int flags, l4id_t id);
typedef int (*__l4_ipc_control_t)(unsigned int action, l4id_t blocked_sender,
u32 blocked_tag);
extern __l4_ipc_control_t __l4_ipc_control;
int l4_ipc_control(unsigned int, l4id_t blocked_sender, u32 blocked_tag);
typedef int (*__l4_exchange_registers_t)(void *exregs_struct, l4id_t tid);
extern __l4_exchange_registers_t __l4_exchange_registers;
int l4_exchange_registers(void *exregs_struct, l4id_t tid);
typedef int (*__l4_container_control_t)(unsigned int req, unsigned int flags, void *buf);
extern __l4_container_control_t __l4_container_control;
int l4_container_control(unsigned int req, unsigned int flags, void *buf);
typedef int (*__l4_time_t)(void *timeval, int set);
extern __l4_time_t __l4_time;
int l4_time(void *timeval, int set);
typedef int (*__l4_mutex_control_t)(void *mutex_word, int op);
extern __l4_mutex_control_t __l4_mutex_control;
int l4_mutex_control(void *mutex_word, int op);
typedef int (*__l4_cache_control_t)(void *start, void *end, unsigned int flags);
extern __l4_cache_control_t __l4_cache_control;
int l4_cache_control(void *start, void *end, unsigned int flags);
/* To be supplied by server tasks. */
void *virt_to_phys(void *);
void *phys_to_virt(void *);
#endif /* __ARM_SYSCALLS_H__ */

View File

@@ -0,0 +1,366 @@
/*
* Helper functions that wrap raw l4 syscalls.
*
* Copyright (C) 2007-2009 Bahadir Bilgehan Balban
*/
#ifndef __L4LIB_SYSLIB_H__
#define __L4LIB_SYSLIB_H__
#include <stdio.h>
#include <l4/macros.h>
#include L4LIB_INC_ARCH(syscalls.h)
/*
* NOTE:
* Its best to use these wrappers because they generalise the way
* common ipc data like sender id, error, ipc tag are passed
* between ipc parties.
*
* The arguments to l4_ipc() are used by the microkernel to initiate
* the ipc. Any data passed in message registers may or may not be
* a duplicate of this data, but the distinction is that anything
* that is passed via the mrs are meant to be used by the other party
* participating in the ipc.
*/
/* For system call arguments */
#define L4SYS_ARG0 (MR_UNUSED_START)
#define L4SYS_ARG1 (MR_UNUSED_START + 1)
#define L4SYS_ARG2 (MR_UNUSED_START + 2)
#define L4SYS_ARG3 (MR_UNUSED_START + 3)
#define L4_IPC_TAG_MASK 0x00000FFF
/*
* Servers get sender.
*/
static inline l4id_t l4_get_sender(void)
{
return (l4id_t)read_mr(MR_SENDER);
}
/*
* When doing an ipc the sender never has to be explicitly set in
* the utcb via this function since this information is found out
* by the microkernel by checking the system caller's id. This is
* only used for restoring the sender on the utcb in order to
* complete an earlier ipc.
*/
static inline void l4_set_sender(l4id_t sender)
{
write_mr(MR_SENDER, sender);
}
static inline unsigned int l4_set_ipc_size(unsigned int word, unsigned int size)
{
word &= ~L4_IPC_FLAGS_SIZE_MASK;
word |= ((size << L4_IPC_FLAGS_SIZE_SHIFT) & L4_IPC_FLAGS_SIZE_MASK);
return word;
}
static inline unsigned int l4_get_ipc_size(unsigned int word)
{
return (word & L4_IPC_FLAGS_SIZE_MASK) >> L4_IPC_FLAGS_SIZE_SHIFT;
}
static inline unsigned int l4_set_ipc_msg_index(unsigned int word, unsigned int index)
{
/* FIXME: Define MR_PRIMARY_TOTAL, MR_TOTAL etc. and use MR_TOTAL HERE! */
BUG_ON(index > UTCB_SIZE);
word &= ~L4_IPC_FLAGS_MSG_INDEX_MASK;
word |= (index << L4_IPC_FLAGS_MSG_INDEX_SHIFT) &
L4_IPC_FLAGS_MSG_INDEX_MASK;
return word;
}
static inline unsigned int l4_get_ipc_msg_index(unsigned int word)
{
return (word & L4_IPC_FLAGS_MSG_INDEX_MASK)
>> L4_IPC_FLAGS_MSG_INDEX_SHIFT;
}
static inline unsigned int l4_set_ipc_flags(unsigned int word, unsigned int flags)
{
word &= ~L4_IPC_FLAGS_TYPE_MASK;
word |= flags & L4_IPC_FLAGS_TYPE_MASK;
return word;
}
static inline unsigned int l4_get_ipc_flags(unsigned int word)
{
return word & L4_IPC_FLAGS_TYPE_MASK;
}
static inline unsigned int l4_get_tag(void)
{
return read_mr(MR_TAG) & L4_IPC_TAG_MASK;
}
static inline void l4_set_tag(unsigned int tag)
{
unsigned int tag_flags = read_mr(MR_TAG);
tag_flags &= ~L4_IPC_TAG_MASK;
tag_flags |= tag & L4_IPC_TAG_MASK;
write_mr(MR_TAG, tag_flags);
}
/* Servers:
* Sets the message register for returning errors back to client task.
* These are usually posix error codes.
*/
static inline void l4_set_retval(int retval)
{
write_mr(MR_RETURN, retval);
}
/* Clients:
* Learn result of request.
*/
static inline int l4_get_retval(void)
{
return read_mr(MR_RETURN);
}
/*
* This is useful for stacked IPC. A stacked IPC happens
* when a new IPC is initiated before concluding the current
* one.
*
* This saves the last ipc's parameters such as the sender
* and tag information. Any previously saved data in save
* slots are destroyed. This is fine as IPC stacking is only
* useful if done once.
*/
static inline void l4_save_ipcregs(void)
{
l4_get_utcb()->saved_sender = l4_get_sender();
l4_get_utcb()->saved_tag = l4_get_tag();
}
static inline void l4_restore_ipcregs(void)
{
l4_set_tag(l4_get_utcb()->saved_tag);
l4_set_sender(l4_get_utcb()->saved_sender);
}
#define TASK_CID_MASK 0xFF000000
#define TASK_ID_MASK 0x00FFFFFF
#define TASK_CID_SHIFT 24
static inline l4id_t __raw_tid(l4id_t tid)
{
return tid & TASK_ID_MASK;
}
static inline l4id_t __cid(l4id_t tid)
{
return (tid & TASK_CID_MASK) >> TASK_CID_SHIFT;
}
static inline l4id_t self_tid(void)
{
struct task_ids ids;
l4_getid(&ids);
return ids.tid;
}
static inline l4id_t __raw_self_tid(void)
{
return __raw_tid(self_tid());
}
static inline int l4_send_full(l4id_t to, unsigned int tag)
{
l4_set_tag(tag);
return l4_ipc(to, L4_NILTHREAD, L4_IPC_FLAGS_FULL);
}
static inline int l4_receive_full(l4id_t from)
{
return l4_ipc(L4_NILTHREAD, from, L4_IPC_FLAGS_FULL);
}
static inline int l4_sendrecv_full(l4id_t to, l4id_t from, unsigned int tag)
{
int err;
BUG_ON(to == L4_NILTHREAD || from == L4_NILTHREAD);
l4_set_tag(tag);
err = l4_ipc(to, from, L4_IPC_FLAGS_FULL);
return err;
}
static inline int l4_send_extended(l4id_t to, unsigned int tag,
unsigned int size, void *buf)
{
unsigned int flags = 0;
l4_set_tag(tag);
/* Set up flags word for extended ipc */
flags = l4_set_ipc_flags(flags, L4_IPC_FLAGS_EXTENDED);
flags = l4_set_ipc_size(flags, size);
flags = l4_set_ipc_msg_index(flags, L4SYS_ARG0);
/* Write buffer pointer to MR index that we specified */
write_mr(L4SYS_ARG0, (unsigned long)buf);
return l4_ipc(to, L4_NILTHREAD, flags);
}
static inline int l4_receive_extended(l4id_t from, unsigned int size, void *buf)
{
unsigned int flags = 0;
/* Indicate extended receive */
flags = l4_set_ipc_flags(flags, L4_IPC_FLAGS_EXTENDED);
/* How much data is accepted */
flags = l4_set_ipc_size(flags, size);
/* Indicate which MR index buffer pointer is stored */
flags = l4_set_ipc_msg_index(flags, L4SYS_ARG0);
/* Set MR with buffer to receive data */
write_mr(L4SYS_ARG0, (unsigned long)buf);
return l4_ipc(L4_NILTHREAD, from, flags);
}
/*
* Return result value as extended IPC.
*
* Extended IPC copies up to 2KB user address space buffers.
* Along with such an ipc, a return value is sent using a primary
* mr that is used as the return register.
*
* It may not be desirable to return a payload on certain conditions,
* (such as an error return value) So a nopayload field is provided.
*/
static inline int l4_return_extended(int retval, unsigned int size,
void *buf, int nopayload)
{
unsigned int flags = 0;
l4id_t sender = l4_get_sender();
l4_set_retval(retval);
/* Set up flags word for extended ipc */
flags = l4_set_ipc_flags(flags, L4_IPC_FLAGS_EXTENDED);
flags = l4_set_ipc_msg_index(flags, L4SYS_ARG0);
/* Write buffer pointer to MR index that we specified */
write_mr(L4SYS_ARG0, (unsigned long)buf);
if (nopayload)
flags = l4_set_ipc_size(flags, 0);
else
flags = l4_set_ipc_size(flags, size);
return l4_ipc(sender, L4_NILTHREAD, flags);
}
static inline int l4_sendrecv_extended(l4id_t to, l4id_t from,
unsigned int tag, void *buf)
{
/* Need to imitate sendrecv but with extended send/recv flags */
return 0;
}
static inline int l4_send(l4id_t to, unsigned int tag)
{
l4_set_tag(tag);
return l4_ipc(to, L4_NILTHREAD, 0);
}
static inline int l4_sendrecv(l4id_t to, l4id_t from, unsigned int tag)
{
int err;
BUG_ON(to == L4_NILTHREAD || from == L4_NILTHREAD);
l4_set_tag(tag);
err = l4_ipc(to, from, 0);
return err;
}
static inline int l4_receive(l4id_t from)
{
return l4_ipc(L4_NILTHREAD, from, 0);
}
static inline void l4_print_mrs()
{
printf("Message registers: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
read_mr(0), read_mr(1), read_mr(2), read_mr(3),
read_mr(4), read_mr(5));
}
/* Servers:
* Return the ipc result back to requesting task.
*/
static inline int l4_ipc_return(int retval)
{
l4id_t sender = l4_get_sender();
l4_set_retval(retval);
/* Setting the tag would overwrite retval so we l4_send without tagging */
return l4_ipc(sender, L4_NILTHREAD, 0);
}
void *l4_new_virtual(int npages);
void *l4_del_virtual(void *virt, int npages);
/* A helper that translates and maps a physical address to virtual */
static inline void *l4_map_helper(void *phys, int npages)
{
struct task_ids ids;
int err;
void *virt = l4_new_virtual(npages);
l4_getid(&ids);
if ((err = l4_map(phys, virt, npages,
MAP_USR_DEFAULT, ids.tid)) < 0)
return PTR_ERR(err);
return virt;
}
/* A helper that translates and maps a physical address to virtual */
static inline void *l4_unmap_helper(void *virt, int npages)
{
struct task_ids ids;
l4_getid(&ids);
l4_unmap(virt, npages, ids.tid);
l4_del_virtual(virt, npages);
return 0;
}
#define L4_EXIT_MASK 0xFFFF
static inline void l4_exit(unsigned int exit_code)
{
struct task_ids ids;
l4_getid(&ids);
l4_thread_control(THREAD_DESTROY |
(exit_code & L4_EXIT_MASK),
&ids);
}
#endif /* __L4LIB_SYSLIB_H__ */

View File

@@ -0,0 +1,8 @@
#ifndef __L4LIB_ARM_TYPES_H___
#define __L4LIB_ARM_TYPES_H__
#define TASK_ID_INVALID 0xFFFFFFFF
#include <l4/arch/arm/types.h>
#endif /* __L4LIB_ARM_TYPES_H__ */

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2009 Bahadir Bilgehan Balban
*/
#ifndef __ARM_UTCB_H__
#define __ARM_UTCB_H__
#define USER_UTCB_REF 0xFF000050
#define L4_KIP_ADDRESS 0xFF000000
#define UTCB_KIP_OFFSET 0x50
#ifndef __ASSEMBLY__
#include <l4lib/types.h>
#include <l4/macros.h>
#include <l4/lib/math.h>
#include INC_GLUE(message.h)
#include INC_GLUE(memory.h)
#include <string.h>
#include <stdio.h>
#include L4LIB_INC_SUBARCH(utcb.h)
/*
* See kernel glue/arch/message.h for utcb details
*/
extern struct kip *kip;
/* Functions to read/write utcb registers */
static inline unsigned int read_mr(int offset)
{
if (offset < MR_TOTAL)
return l4_get_utcb()->mr[offset];
else
return l4_get_utcb()->mr_rest[offset - MR_TOTAL];
}
static inline void write_mr(unsigned int offset, unsigned int val)
{
if (offset < MR_TOTAL)
l4_get_utcb()->mr[offset] = val;
else
l4_get_utcb()->mr_rest[offset - MR_TOTAL] = val;
}
static inline void *utcb_full_buffer()
{
return &l4_get_utcb()->mr_rest[0];
}
static inline char *utcb_full_strcpy_from(const char *src)
{
return strncpy((char *)&l4_get_utcb()->mr_rest[0], src,
L4_UTCB_FULL_BUFFER_SIZE);
}
static inline void *utcb_full_memcpy_from(const char *src, int size)
{
return memcpy(&l4_get_utcb()->mr_rest[0], src,
min(size, L4_UTCB_FULL_BUFFER_SIZE));
}
static inline char *utcb_full_strcpy_to(char *dst)
{
return strncpy(dst, (char *)&l4_get_utcb()->mr_rest[0],
L4_UTCB_FULL_BUFFER_SIZE);
}
static inline void *utcb_full_memcpy_to(char *dst, int size)
{
return memcpy(dst, &l4_get_utcb()->mr_rest[0],
min(size, L4_UTCB_FULL_BUFFER_SIZE));
}
#endif /* !__ASSEMBLY__ */
#endif /* __ARM_UTCB_H__ */

View File

@@ -0,0 +1,3 @@
#ifndef __PERFMON_H__
#endif

View File

@@ -0,0 +1,21 @@
#ifndef __ARM_V5_UTCB_H__
#define __ARM_V5_UTCB_H__
/*
* Pointer to Kernel Interface Page's UTCB pointer offset.
*/
extern struct utcb **kip_utcb_ref;
static inline struct utcb *l4_get_utcb()
{
/*
* By double dereferencing, we get the private TLS
* (aka UTCB). First reference is to the KIP's utcb
* offset, second is to the utcb itself, to which
* the KIP's utcb reference had been updated during
* context switch.
*/
return *kip_utcb_ref;
}
#endif /* __ARM_V5_UTCB_H__ */

View File

@@ -0,0 +1,405 @@
/*
* ARMv7 Performance Monitor operations
*
* Copyright (C) 2010 B Labs Ltd.
*
* Author: Bahadir Balban
*/
#ifndef __PERFMON_H__
#define __PERFMON_H__
#include <l4lib/types.h>
/* Perfmon control register */
#define PMCR_DP_BIT 5 /* Disable prohibited */
#define PMCR_X_BIT 4 /* Export event enable */
#define PMCR_D_BIT 3 /* 64-cycle granularity */
#define PMCR_C_BIT 2 /* PMCCNTR reset */
#define PMCR_P_BIT 1 /* Events all reset */
#define PMCR_E_BIT 0 /* Enable all */
/* Obtain number of event counters */
#define PMCR_N_SHIFT 11
#define PMCR_N_MASK 0x1F
/* Special bit for cycle counter */
#define PMCCNTR_BIT 31
/*
* Performance Events
*/
/* Generic v7 events */
#define PERFMON_EVENT_SOFTINC 0
#define PERFMON_EVENT_IFETCH_L1CREFILL 1
#define PERFMON_EVENT_IFETCH_TLBREFILL 2
#define PERFMON_EVENT_DFETCH_L1CREFILL 3
#define PERFMON_EVENT_DFETCH_L1CACCESS 4
#define PERFMON_EVENT_DFETCH_TLBREFILL 5
#define PERFMON_EVENT_MEMREAD_INSTR 6
#define PERFMON_EVENT_MEMWRITE_INSTR 7
#define PERFMON_EVENT_ALL_INSTR 8
#define PERFMON_EVENT_EXCEPTION 9
#define PERFMON_EVENT_EXCEPTION_RETURN 10
#define PERFMON_EVENT_CONTEXTIDR_CHANGE 11
#define PERFMON_EVENT_PC_CHANGE 12
#define PERFMON_EVENT_IMM_BRANCH 13
#define PERFMON_EVENT_FUNCTION_RETURN 14
#define PERFMON_EVENT_UNALIGNED_ACCESS 15
#define PERFMON_EVENT_BRANCH_MISS 16
#define PERFMON_EVENT_RAW_CYCLE_COUNT 17
#define PERFMON_EVENT_BRANCH_MAYBEHIT 18
/*
* Cortex-A9 events (only relevant ones)
* 0x40-2, 0x6E, 0x70, 0x71-4, 0x80-0x81, 0x8A-8B
* 0xA0-5 omitted
*/
/*
* Linefill not satisfied from other cpu caches but
* has to go to external memory
*/
#define PERFMON_EVENT_SMP_LINEFILL_MISS 0x50
/* Linefill satisfied from other cpu caches */
#define PERFMON_EVENT_SMP_LINEFILL_HIT 0x51
/* Icache refill stall cycles on cpu pipeline */
#define PERFMON_EVENT_ICACHE_CPU_STALL 0x60
/* Dcache refill stall cycles on cpu pipeline */
#define PERFMON_EVENT_DCACHE_CPU_STALL 0x61
/* TLB miss stall cycles on cpu pipeline */
#define PERFMON_EVENT_TLBMISS_CPU_STALL 0x62
#define PERFMON_EVENT_STREX_SUCCESS 0x63
#define PERFMON_EVENT_STREX_FAIL 0x64
#define PERFMON_EVENT_DCACHE_EVICTION 0x65
/* Issue stage can't proceed to dispatch any instruction */
#define PERFMON_EVENT_PIPELINE_CANT_ISSUE 0x66
/* Issue stage empty */
#define PERFMON_EVENT_PIPELINE_ISSUE_EMPTY 0x67
/* Register renamed instructions */
#define PERFMON_EVENT_REGRENAMED_INSTR 0x68
#define PERFMON_EVENT_CPUSTALL_ITLB_MISS 0x82
#define PERFMON_EVENT_CPUSTALL_DTLB_MISS 0x83
#define PERFMON_EVENT_CPUSTALL_IUTLB_MISS 0x84
#define PERFMON_EVENT_CPUSTALL_DUTLB_MISS 0x85
#define PERFMON_EVENT_CPUSTALL_DMB 0x86
#define PERFMON_EVENT_ISB_COUNT 0x90
#define PERFMON_EVENT_DSB_COUNT 0x91
#define PERFMON_EVENT_DMB_COUNT 0x92
#define PERFMON_EVENT_EXTIRQ_COUNT 0x93
static inline u32 __attribute__((always_inline))
cp15_read_perfmon_ctrl(void)
{
volatile u32 val = 0;
__asm__ __volatile__ (
"mrc p15, 0, %0, c9, c12, 0\n"
"isb\n"
: "=r" (val)
:
);
return val;
}
static inline void __attribute__((always_inline))
cp15_write_perfmon_ctrl(volatile u32 word)
{
__asm__ __volatile__ (
"mcr p15, 0, %0, c9, c12, 0"
:
: "r" (word)
);
}
static inline u32 __attribute__((always_inline))
cp15_read_perfmon_cntenset(void)
{
volatile u32 val = 0;
__asm__ __volatile__ (
"mrc p15, 0, %0, c9, c12, 1\n"
"isb\n"
: "=r" (val)
:
);
return val;
}
static inline void __attribute__((always_inline))
cp15_write_perfmon_cntenset(volatile u32 word)
{
__asm__ __volatile__ (
"mcr p15, 0, %0, c9, c12, 1"
:
: "r" (word)
);
}
static inline u32 __attribute__((always_inline))
cp15_read_perfmon_cntenclr(void)
{
u32 val = 0;
__asm__ __volatile__ (
"mrc p15, 0, %0, c9, c12, 2"
: "=r" (val)
:
);
return val;
}
static inline void __attribute__((always_inline))
cp15_write_perfmon_cntenclr(volatile u32 word)
{
__asm__ __volatile__ (
"mcr p15, 0, %0, c9, c12, 2"
:
: "r" (word)
);
}
static inline u32 __attribute__((always_inline))
cp15_read_perfmon_overflow(void)
{
u32 val = 0;
__asm__ __volatile__ (
"mrc p15, 0, %0, c9, c12, 3"
: "=r" (val)
:
);
return val;
}
static inline void __attribute__((always_inline))
cp15_write_perfmon_overflow(volatile u32 word)
{
__asm__ __volatile__ (
"mcr p15, 0, %0, c9, c12, 3"
:
: "r" (word)
);
}
static inline void __attribute__((always_inline))
cp15_write_perfmon_softinc(volatile u32 word)
{
__asm__ __volatile__ (
"mcr p15, 0, %0, c9, c12, 4"
:
: "r" (word)
);
}
static inline u32 __attribute__((always_inline))
cp15_read_perfmon_evcntsel(void)
{
u32 val = 0;
__asm__ __volatile__ (
"mrc p15, 0, %0, c9, c12, 5"
: "=r" (val)
:
);
return val;
}
static inline void __attribute__((always_inline))
cp15_write_perfmon_evcntsel(volatile u32 word)
{
__asm__ __volatile__ (
"mcr p15, 0, %0, c9, c12, 5"
:
: "r" (word)
);
}
static inline u32 __attribute__((always_inline))
cp15_read_perfmon_cyccnt(void)
{
volatile u32 val = 0;
__asm__ __volatile__ (
"mrc p15, 0, %0, c9, c13, 0\n"
"isb\n"
: "=r" (val)
:
);
return val;
}
static inline void __attribute__((always_inline))
cp15_write_perfmon_cyccnt(volatile u32 word)
{
__asm__ __volatile__ (
"mcr p15, 0, %0, c9, c13, 0"
:
: "r" (word)
);
}
static inline u32 __attribute__((always_inline))
cp15_read_perfmon_evtypesel(void)
{
u32 val = 0;
__asm__ __volatile__ (
"mrc p15, 0, %0, c9, c13, 1"
: "=r" (val)
:
);
return val;
}
static inline void __attribute__((always_inline))
cp15_write_perfmon_evtypesel(volatile u32 word)
{
__asm__ __volatile__ (
"mcr p15, 0, %0, c9, c13, 1"
:
: "r" (word)
);
}
static inline u32 __attribute__((always_inline))
cp15_read_perfmon_evcnt(void)
{
u32 val = 0;
__asm__ __volatile__ (
"mrc p15, 0, %0, c9, c13, 2"
: "=r" (val)
:
);
return val;
}
static inline void __attribute__((always_inline))
cp15_write_perfmon_evcnt(volatile u32 word)
{
__asm__ __volatile__ (
"mcr p15, 0, %0, c9, c13, 2"
:
: "r" (word)
);
}
static inline u32 __attribute__((always_inline))
cp15_read_perfmon_useren(void)
{
u32 val = 0;
__asm__ __volatile__ (
"mrc p15, 0, %0, c9, c14, 0"
: "=r" (val)
:
);
return val;
}
static inline void __attribute__((always_inline))
cp15_write_perfmon_useren(volatile u32 word)
{
__asm__ __volatile__ (
"mcr p15, 0, %0, c9, c14, 0"
:
: "r" (word)
);
}
static inline u32 __attribute__((always_inline))
cp15_read_perfmon_intenset(void)
{
u32 val = 0;
__asm__ __volatile__ (
"mrc p15, 0, %0, c9, c14, 1"
: "=r" (val)
:
);
return val;
}
static inline void __attribute__((always_inline))
cp15_write_perfmon_intenset(volatile u32 word)
{
__asm__ __volatile__ (
"mcr p15, 0, %0, c9, c14, 1"
:
: "r" (word)
);
}
static inline u32 __attribute__((always_inline))
cp15_read_perfmon_intenclr(void)
{
u32 val = 0;
__asm__ __volatile__ (
"mrc p15, 0, %0, c9, c14, 2"
: "=r" (val)
:
);
return val;
}
static inline void __attribute__((always_inline))
cp15_write_perfmon_intenclr(volatile u32 word)
{
__asm__ __volatile__ (
"mcr p15, 0, %0, c9, c14, 2"
:
: "r" (word)
);
}
#include <stdio.h>
#if defined (CONFIG_DEBUG_PERFMON_USER)
static inline
u32 perfmon_read_cyccnt()
{
u32 cnt = cp15_read_perfmon_cyccnt();
u32 ovfl = cp15_read_perfmon_overflow();
/* Detect overflow and signal something was wrong */
if (ovfl & (1 << PMCCNTR_BIT))
printf("%s: Overflow.\n", __FUNCTION__);
return cnt;
}
void perfmon_reset_start_cyccnt();
u32 perfmon_read_reset_start_cyccnt();
#endif
void perfmon_init();
#endif /* __PERFMON_H__ */

View File

@@ -0,0 +1,59 @@
#ifndef __ARM_V5_UTCB_H__
#define __ARM_V5_UTCB_H__
/*
* NOTE: Any changes you make here, you *MUST* change
* utcb_address() macro in syscall.S assembler.
*/
/* Read Thread ID User RW register */
static inline u32 l4_cp15_read_tid_usr_rw(void)
{
volatile u32 val;
__asm__ __volatile__ (
"mrc p15, 0, %0, c13, c0, 2"
: "=r" (val)
:
);
return val;
}
/* Write Thread ID User RW register */
static inline void l4_cp15_write_tid_usr_rw(volatile u32 val)
{
__asm__ __volatile__ (
"mcr p15, 0, %0, c13, c0, 2"
:
: "r" (val)
);
}
/* Read Thread ID User RO register */
static inline u32 l4_cp15_read_tid_usr_ro(void)
{
volatile u32 val;
__asm__ __volatile__ (
"mrc p15, 0, %0, c13, c0, 3"
: "=r" (val)
:
);
return val;
}
/*
* In ARMv7, utcb resides in the userspace read-only
* thread register. This adds the benefit of avoiding
* dirtying the cache and extra management for smp since
* it is per-cpu.
*/
static inline struct utcb *l4_get_utcb()
{
// printf("%s: UTCB Adddress: 0x%x\n", __FUNCTION__, l4_cp15_read_tid_usr_ro());
return (struct utcb *)l4_cp15_read_tid_usr_ro();
}
#endif /* __ARM_V5_UTCB_H__ */

View File

@@ -0,0 +1,13 @@
/*
* Cache control operations
*
* Copyright (C) 2009 Bora Sahin
*/
#ifndef __L4_CACHE_CONTROL__
#define __L4_CACHE_CONTROL__
#include <l4/api/cache.h>
#endif /* __L4_CACHE_CONTROL__ */

View File

@@ -8,7 +8,10 @@ void exregs_set_mr(struct exregs_data *s, int offset, unsigned long val);
void exregs_set_pc(struct exregs_data *s, unsigned long pc);
void exregs_set_pager(struct exregs_data *s, l4id_t pagerid);
void exregs_set_utcb(struct exregs_data *s, unsigned long virt);
void exregs_set_read(struct exregs_data *exregs);
unsigned long exregs_get_utcb(struct exregs_data *s);
unsigned long exregs_get_stack(struct exregs_data *s);
/*
exregs_set_stack(unsigned long sp)
exregs_set_pc(unsigned long pc)

View File

@@ -10,6 +10,7 @@
#define __IPCDEFS_H__
#include <l4/api/ipc.h>
#include <l4lib/types.h>
/*** IPC Tags used between server tasks ***/
@@ -69,7 +70,8 @@ extern l4id_t pagerid;
#define L4_IPC_TAG_UART_RECVBUF 54 /* Buffered recv */
/* For ipc to timer service (TODO: Shared mapping buffers???) */
#define L4_IPC_TAG_TIMER_GETTIME 55
#define L4_IPC_TAG_TIMER_SLEEP 56
#define L4_IPC_TAG_TIMER_GETTIME 55
#define L4_IPC_TAG_TIMER_SLEEP 56
#define L4_IPC_TAG_TIMER_WAKE_THREADS 57
#endif /* __IPCDEFS_H__ */

View File

@@ -9,7 +9,7 @@
/* Use the kernel header */
#include <l4lib/types.h>
#include <l4lib/arch/syscalls.h>
#include <l4/api/kip.h>
#include L4LIB_INC_ARCH(syscalls.h)
#endif /* __KIP_H__ */

View File

@@ -0,0 +1,27 @@
/*
* Address allocation pool.
*
* Copyright (C) 2007 Bahadir Balban
*/
#ifndef __ADDR_H__
#define __ADDR_H__
#include <l4lib/lib/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(struct address_pool *pool,
struct id_pool *idpool,
unsigned long start, unsigned long end);
int address_pool_alloc_init(struct address_pool *pool,
unsigned long start, unsigned long end,
unsigned 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,75 @@
/*
* Capability-related management.
*
* Copyright (C) 2009 Bahadir Balban
*/
#ifndef __LIBL4_CAPABILITY_H__
#define __LIBL4_CAPABILITY_H__
#include <l4lib/types.h>
#include <l4/lib/list.h>
#include <l4/api/capability.h>
#include <l4/generic/cap-types.h>
void cap_dev_print(struct capability *cap);
void cap_print(struct capability *cap);
void cap_array_print(int total_caps, struct capability *caparray);
/*
* Definitions for lists of capabilities
*/
struct cap_list {
int ncaps;
struct link caps;
};
static inline void cap_list_init(struct cap_list *clist)
{
clist->ncaps = 0;
link_init(&clist->caps);
}
static inline void cap_list_insert(struct capability *cap,
struct cap_list *clist)
{
list_insert(&cap->list, &clist->caps);
clist->ncaps++;
}
/* Detach a whole list of capabilities from list head */
static inline struct capability *
cap_list_detach(struct cap_list *clist)
{
struct link *list = list_detach(&clist->caps);
clist->ncaps = 0;
return link_to_struct(list, struct capability, list);
}
/* Attach a whole list of capabilities to list head */
static inline void cap_list_attach(struct capability *cap,
struct cap_list *clist)
{
/* Attach as if cap is the list and clist is the element */
list_insert(&clist->caps, &cap->list);
/* Count the number of caps attached */
list_foreach_struct(cap, &clist->caps, list)
clist->ncaps++;
}
static inline void cap_list_move(struct cap_list *to,
struct cap_list *from)
{
struct capability *cap_head = cap_list_detach(from);
cap_list_attach(cap_head, to);
}
/*
* Definitions for reading from the library capability array
*/
void __l4_capability_init(void);
struct capability *cap_get_by_type(unsigned int cap_type);
struct capability *cap_get_physmem(unsigned int cap_type);
#endif /* __LIBL4_CAPABILITY_H__ */

View File

@@ -0,0 +1,32 @@
#ifndef __IDPOOL_H__
#define __IDPOOL_H__
#include <l4lib/lib/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));
}
void id_pool_init(struct id_pool *idpool, int bits);
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,65 @@
#ifndef __THREAD_H__
#define __THREAD_H__
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(syslib.h)
#include L4LIB_INC_ARCH(syscalls.h)
#include <l4lib/exregs.h>
#include <l4lib/mutex.h>
#include <l4/api/thread.h>
#include <l4/lib/list.h>
/*
* Library specific-flags for thread creation
*/
#define TC_USER_FLAGS_MASK 0x000F0000
#define TC_NOSTART 0x00010000
/* For same space */
#define STACK_SIZE PAGE_SIZE
/* Total threads the library supports */
#define THREADS_TOTAL 10
/*
* Keeps track of threads in the system
* created by the pager
*/
struct l4_thread_list {
int total; /* Total number of threads */
struct l4_mutex lock; /* Threads list lock */
struct link thread_list; /* Threads list */
struct mem_cache *thread_cache; /* Cache for thread structures */
};
struct l4_thread {
struct task_ids ids; /* Thread ids */
struct l4_mutex lock; /* Lock for thread struct */
struct link list; /* Link to list of threads */
unsigned long *stack; /* Stack (grows downwards) */
struct utcb *utcb; /* UTCB address */
};
/*
* These are thread calls that are meant to be
* called by library users
*/
int thread_create(int (*func)(void *), void *args, unsigned int flags,
struct l4_thread **tptr);
int thread_wait(struct l4_thread *t);
void thread_exit(int exitcode);
/*
* This is to be called only if to-be-destroyed thread is in
* sane condition for destruction
*/
int thread_destroy(struct l4_thread *thread);
/* Library init function called by __container_init */
void __l4_threadlib_init(void);
void l4_parent_thread_init(void);
extern struct mem_cache *utcb_cache, *stack_cache;
extern struct l4_thread_list l4_thread_list;
extern void setup_new_thread(void);
#endif /* __THREAD_H__ */

View File

@@ -0,0 +1,25 @@
/*
* Userspace-specific macros.
*
* Copyright (C) 2010 B Labs Ltd.
*/
#ifndef __LIBL4_MACROS_H__
#define __LIBL4_MACROS_H__
#include <l4/config.h>
/*
* These are for the userspace code to include
* different directories based on configuration
* values for platform, architecture and so on.
*
* This file is meant to be included from all
* userspace projects by default.
*/
#define L4LIB_INC_ARCH(x) <l4lib/arch/__ARCH__/x>
#define L4LIB_INC_SUBARCH(x) <l4lib/arch/__ARCH__/__SUBARCH__/x>
#define L4LIB_INC_PLAT(x) <l4lib/platform/__PLATFORM__/x>
#define L4LIB_INC_GLUE(x) <l4lib/glue/__ARCH__/x>
#endif /* __LIBL4_MACROS_H__ */

View File

@@ -0,0 +1,13 @@
#include <l4lib/macros.h>
#include L4LIB_INC_SUBARCH(perfmon.h)
#if !defined (CONFIG_DEBUG_PERFMON_USER)
/* Common empty definitions for all arches */
static inline u32 perfmon_read_cyccnt() { return 0; }
static inline void perfmon_reset_start_cyccnt() { }
static inline u32 perfmon_read_reset_start_cyccnt() { return 0; }
#endif

View File

@@ -1,6 +1,7 @@
#ifndef __TYPES_H__
#define __TYPES_H__
#include <l4lib/arch/types.h>
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(types.h)
#endif /* __TYPES_H__ */

View File

@@ -5,7 +5,8 @@
#define __UTCB_H__
#include <l4lib/types.h>
#include <l4lib/arch/utcb.h>
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(utcb.h)
int utcb_init(void);

View File

@@ -0,0 +1,99 @@
/*
* Generic to arch-specific interface for
* exchange_registers()
*
* Copyright (C) 2008 Bahadir Balban
*/
#include <l4/macros.h>
#include <l4lib/exregs.h>
#include L4LIB_INC_ARCH(syslib.h)
#include INC_GLUE(message.h)
void exregs_set_read(struct exregs_data *exregs)
{
exregs->flags |= EXREGS_READ;
}
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;
}
unsigned long exregs_get_utcb(struct exregs_data *s)
{
return s->utcb_address;
}
unsigned long exregs_get_stack(struct exregs_data *s)
{
return s->context.sp;
}
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);
}

View File

@@ -0,0 +1,21 @@
/*
* Set up new thread's argument and call its function.
* Return would be made to thread_exit with the return code.
*
* Copyright (C) 2010 B Labs Ltd.
*
* Author: Bahadir Balban
*/
#include <l4lib/macros.h>
#include L4LIB_INC_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 thread_exit @ Call l4_thread_exit for cleanup
1:
b 1b @ Never reaches here
END_PROC(setup_new_thread)

View File

@@ -0,0 +1,235 @@
/*
* Userspace system call interface.
*
* Copyright (C) 2007 - 2009 Bahadir Balban
*/
#include L4LIB_INC_ARCH(asm.h)
#include L4LIB_INC_ARCH(utcb.h)
#include <l4/generic/space.h>
#include <l4/macros.h>
#include INC_GLUE(message.h)
#if defined (CONFIG_ARCH_ARM) && defined (CONFIG_SUBARCH_V7)
/* ARMv7 uses a special per-cpu register to keep thread-local utcb pointer */
.macro utcb_address rx
mrc p15, 0, \rx, c13, c0, 3 @ Read user-RO thread register TPIDRURO
.endm
#else /* End of ARMv7 */
/* Get it from KIP page by 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
#endif
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)
/*
* System call that manipulates caches and tlbs.
*
* @r0 = starting virtual address (inclusive),
* @r1 = ending virtual address (exclusive),
* @r3 = cache operation
*/
BEGIN_PROC(l4_cache_control)
stmfd sp!, {lr}
ldr r12, =__l4_cache_control
mov lr, pc
ldr pc, [r12]
ldmfd sp!, {pc} @ Restore original lr and return.
END_PROC(l4_cache_control)

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2009-2010 B Labs Ltd.
* Author: Bahadir Balban
*/
#include L4LIB_INC_ARCH(asm.h)
#include <l4lib/mutex.h>
#include <l4lib/types.h>
#include INC_SUBARCH(irq.h)
#include L4LIB_INC_ARCH(syslib.h) /* for BUG/BUG_ON, */
/*
* 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.
*/
int __l4_mutex_lock(void *m, l4id_t tid)
{
unsigned int tmp;
__asm__ __volatile__(
"swp %0, %1, [%2]"
: "=r" (tmp)
: "r"(tid), "r" (m)
: "memory"
);
if (tmp == L4_MUTEX_UNLOCKED)
return L4_MUTEX_SUCCESS;
return L4_MUTEX_CONTENDED;
}
int __l4_mutex_unlock(void *m, l4id_t tid)
{
unsigned int tmp, tmp2 = L4_MUTEX_UNLOCKED;
__asm__ __volatile__(
"swp %0, %1, [%2]"
: "=r" (tmp)
: "r" (tmp2), "r"(m)
: "memory"
);
BUG_ON(tmp == L4_MUTEX_UNLOCKED);
if (tmp == tid)
return L4_MUTEX_SUCCESS;
return L4_MUTEX_CONTENDED;
}
u8 l4_atomic_dest_readb(unsigned long *location)
{
#if 0
unsigned int tmp;
__asm__ __volatile__ (
"swpb r0, r2, [r1] \n"
: "=r"(tmp)
: "r"(location), "r"(0)
: "memory"
);
return (u8)tmp;
#endif
unsigned int tmp;
// unsigned long state;
// irq_local_disable_save(&state);
tmp = *location;
*location = 0;
//irq_local_restore(state);
return (u8)tmp;
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2010 B Labs Ltd.
* Author: Prem Mallappa <prem.mallappa@b-labs.co.uk>
*/
#include <l4lib/mutex.h>
#include <l4lib/types.h>
#include L4LIB_INC_ARCH(syslib.h) /* for BUG/BUG_ON, */
#include L4LIB_INC_ARCH(asm.h)
#include INC_SUBARCH(mmu_ops.h)
int __l4_mutex_lock(void *m, l4id_t tid)
{
int tmp, ret;
loop:
__asm__ __volatile__(
"ldrex %0, [%1]\n"
: "=r"(tmp)
: "r"(m)
);
if(tmp != L4_MUTEX_UNLOCKED)
ret = L4_MUTEX_CONTENDED;
else
ret = L4_MUTEX_SUCCESS;
/* Store our 'tid' */
__asm__ __volatile__(
"strex %0, %1, [%2]\n"
:"=&r"(tmp)
:"r"(tid), "r"(m)
);
if (tmp != 0) {
/* We couldn't succeed the store, we retry */
#ifdef CONFIG_SMP
/* don't hog the CPU, sleep till an event */
__asm__ __volatile__("wfe\n");
#endif
goto loop;
}
dsb();
return ret;
}
int __l4_mutex_unlock(void *m, l4id_t tid)
{
int tmp, ret;
loop:
/* Load and see if the lock had our tid */
__asm__ __volatile__(
"ldrex %0, [%1]\n"
: "=r"(tmp)
: "r"(m)
);
if(tmp != tid)
ret = L4_MUTEX_CONTENDED;
else
ret = L4_MUTEX_SUCCESS;
/* We store unlock value '0' */
__asm__ __volatile__(
"strex %0, %1, [%2]\n"
:"=&r"(tmp)
:"rI"(L4_MUTEX_UNLOCKED), "r"(m)
);
if(tmp != 0) {
/* The store wasn't successfull, retry */
goto loop;
}
dsb();
#ifdef CONFIG_SMP
__asm__ __volatile__("sev\n");
#endif
return ret;
}
u8 l4_atomic_dest_readb(u8 *location)
{
unsigned int tmp, res;
__asm__ __volatile__ (
"1: \n"
"ldrex %0, [%2] \n"
"strex %1, %3, [%2] \n"
"teq %1, #0 \n"
"bne 1b \n"
: "=&r"(tmp), "=&r"(res)
: "r"(location), "r"(0)
: "cc", "memory"
);
return (u8)tmp;
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2009 Bahadir Balban
*/
#include <l4lib/arch/arm/asm.h>
#include <l4lib/mutex.h>
/*
* @r0 = address of mutex word
* @r1 = unique tid of current thread
*/
BEGIN_PROC(__l4_mutex_lock)
1:
ldrex r2, [r0] @ Load value
cmp r2, #L4_MUTEX_UNLOCKED @ Decide what state lock will be if we succeed in a store
movne r2, #L4_MUTEX_CONTENDED
moveq r2, #L4_MUTEX_SUCCESS
strex r3, r1, [r0] @ Store prospective lock state
cmp r3, #0 @ If not successful
@ No WFE. Whatif this were between 2 threads running on the same cpu
bne 1b @ Retry and decide again on the prospective lock state.
dsb
mov r0, r2
mov pc, lr
END_PROC(__l4_mutex_lock)
/*
* @r0 = address of mutex word
* @r1 = unique tid of current thread
*/
BEGIN_PROC(__l4_mutex_unlock)
dsb
push {r4}
mov r4, #L4_MUTEX_UNLOCKED
1:
ldrex r2, [r0]
cmp r2, r1
moveq r3, #L4_MUTEX_SUCCESS
movne r3, #L4_MUTEX_CONTENDED
strex r2, r4, [r0]
cmp r2, #0
bne 1b
mov r0, r3
pop {r4}
mov pc, lr
END_PROC(__l4_mutex_unlock)

View File

@@ -0,0 +1,45 @@
/*
* Performance monitoring
*
* Copyright (C) 2010 B Labs Ltd.
*
* Author: Bahadir Balban
*/
#include <l4lib/perfmon.h>
#if defined (CONFIG_DEBUG_PERFMON_USER)
/*
* Resets/restarts cycle counter
*/
void perfmon_reset_start_cyccnt()
{
volatile u32 pmcctrl;
/* Disable the cycle counter register */
cp15_write_perfmon_cntenclr(1 << PMCCNTR_BIT);
/* Clear the cycle counter on ctrl register */
pmcctrl = cp15_read_perfmon_ctrl();
pmcctrl |= (1 << PMCR_C_BIT);
cp15_write_perfmon_ctrl(pmcctrl);
/* Clear overflow register */
cp15_write_perfmon_overflow(1 << PMCCNTR_BIT);
/* Enable the cycle count */
cp15_write_perfmon_cntenset(1 << PMCCNTR_BIT);
}
/*
* Reads current counter, clears and restarts it
*/
u32 perfmon_read_reset_start_cyccnt()
{
volatile u32 cyccnt = cp15_read_perfmon_cyccnt();
perfmon_reset_start_cyccnt();
return cyccnt;
}
#endif /* End of !CONFIG_DEBUG_PERFMON_USER */

View File

@@ -4,8 +4,8 @@
* Copyright (C) 2007-2009 Bahadir Bilgehan Balban
*/
#include <l4lib/kip.h>
#include <l4lib/arch/syslib.h>
#include <l4lib/arch/utcb.h>
#include L4LIB_INC_ARCH(syslib.h)
#include L4LIB_INC_ARCH(utcb.h)
#include <l4lib/ipcdefs.h>
#include <l4/macros.h>
#include INC_GLUE(memlayout.h)
@@ -24,6 +24,7 @@ __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;
__l4_cache_control_t __l4_cache_control = 0;
struct kip *kip;
@@ -60,5 +61,6 @@ void __l4_init(void)
(__l4_container_control_t)kip->container_control;
__l4_time = (__l4_time_t)kip->time;
__l4_mutex_control = (__l4_mutex_control_t)kip->mutex_control;
__l4_cache_control = (__l4_cache_control_t)kip->cache_control;
}

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <l4lib/arch/irq.h>
#include <l4lib/arch/syscalls.h>
#include L4LIB_INC_ARCH(irq.h)
#include L4LIB_INC_ARCH(syscalls.h)
#include <l4/api/irq.h>
/*
@@ -13,7 +13,7 @@
*/
int l4_irq_wait(int slot, int irqnum)
{
int irqval = l4_atomic_dest_readb(&l4_get_utcb()->notify[slot]);
int irqval = l4_atomic_dest_readb(&(l4_get_utcb()->notify[slot]));
if (!irqval)
return l4_irq_control(IRQ_CONTROL_WAIT, 0, irqnum);

View File

@@ -0,0 +1,62 @@
/*
* This module allocates an unused address range from
* a given memory region defined as the pool range.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4lib/lib/addr.h>
#include <stdio.h>
/*
* Initializes an address pool, but uses an already
* allocated id pool for it.
*/
int address_pool_init(struct address_pool *pool,
struct id_pool *idpool,
unsigned long start, unsigned long end)
{
pool->idpool = idpool;
pool->start = start;
pool->end = end;
id_pool_init(idpool, __pfn(end - start));
return 0;
}
/*
* Allocates an id pool and initializes it
*/
int address_pool_alloc_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;
}

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

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

View File

@@ -0,0 +1,179 @@
/*
* Capability-related userspace helpers
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(syscalls.h)
#include <l4lib/lib/cap.h>
#include <stdio.h>
/* A static limit to total capabilities held by the library */
#define CAPS_TOTAL 64
static struct capability cap_array[CAPS_TOTAL];
static int total_caps = 0;
struct capability *cap_get_by_type(unsigned int cap_type)
{
for (int i = 0; i < total_caps; i++)
if (cap_type(&cap_array[i]) == cap_type)
return &cap_array[i];
return 0;
}
struct capability *cap_get_physmem(unsigned int cap_type)
{
for (int i = 0; i < total_caps; i++)
if ((cap_type(&cap_array[i]) == CAP_TYPE_MAP_PHYSMEM) &&
!cap_is_devmem(&cap_array[i])) {
return &cap_array[i];
}
return 0;
}
/*
* Read all capabilities
*/
int caps_read_all(void)
{
int err;
/* Read number of capabilities */
if ((err = l4_capability_control(CAP_CONTROL_NCAPS,
0, &total_caps)) < 0) {
printf("l4_capability_control() reading # of"
" capabilities failed.\n Could not "
"complete CAP_CONTROL_NCAPS request.\n");
return err;
}
if (total_caps > CAPS_TOTAL) {
printf("FATAL: More capabilities defined for the "
"container than the libl4 static limit. libl4 "
"limit=%d, actual = %d\n", CAPS_TOTAL, total_caps);
BUG();
}
/* Read all capabilities */
if ((err = l4_capability_control(CAP_CONTROL_READ,
0, cap_array)) < 0) {
printf("l4_capability resource_control() reading of "
"capabilities failed.\n Could not "
"complete CAP_CONTROL_READ request.\n");
return err;
}
//cap_array_print(ncaps, caparray);
return 0;
}
void __l4_capability_init(void)
{
caps_read_all();
}
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;
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;
default:
printf("Capability type:\t\t%s\n", "Unknown");
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\n", "Unknown");
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");
}

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,93 @@
/*
* Used for thread and space ids, and also for
* utcb tracking in page-sized-chunks.
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <stdio.h>
#include <l4lib/lib/idpool.h>
#include <l4/api/errno.h>
#include <malloc/malloc.h>
void id_pool_init(struct id_pool *pool, int totalbits)
{
pool->nwords = BITWISE_GETWORD(totalbits) + 1;
pool->bitlimit = totalbits;
}
struct id_pool *id_pool_new_init(int totalbits)
{
int nwords = BITWISE_GETWORD(totalbits) + 1;
struct id_pool *new = kzalloc((nwords * SZ_WORD)
+ sizeof(struct id_pool));
if (!new)
return PTR_ERR(-ENOMEM);
new->nwords = nwords;
new->bitlimit = totalbits;
return new;
}
/* Search for a free slot up to the limit given */
int id_new(struct id_pool *pool)
{
return find_and_set_first_free_bit(pool->bitmap, pool->bitlimit);
}
/* This finds n contiguous free ids, allocates and returns the first one */
int ids_new_contiguous(struct id_pool *pool, int numids)
{
int id = find_and_set_first_free_contig_bits(pool->bitmap,
pool->bitlimit,
numids);
if (id < 0)
printf("%s: Warning! New id alloc failed\n", __FUNCTION__);
return id;
}
/* This deletes a list of contiguous ids given the first one and number of ids */
int ids_del_contiguous(struct id_pool *pool, int first, int numids)
{
int ret;
if (pool->nwords * WORD_BITS < first + numids)
return -1;
if ((ret = check_and_clear_contig_bits(pool->bitmap, first, numids)))
printf("%s: Error: Invalid argument range.\n", __FUNCTION__);
return ret;
}
int id_del(struct id_pool *pool, int id)
{
int ret;
if (pool->nwords * WORD_BITS < id)
return -1;
if ((ret = check_and_clear_bit(pool->bitmap, id) < 0))
printf("%s: Error: Could not delete id.\n", __FUNCTION__);
return ret;
}
/* Return a specific id, if available */
int id_get(struct id_pool *pool, int id)
{
int ret;
ret = check_and_set_bit(pool->bitmap, id);
if (ret < 0)
return ret;
else
return id;
}
int id_is_empty(struct id_pool *pool)
{
for (int i = 0; i < pool->nwords; i++)
if (pool->bitmap[i])
return 0;
return 1;
}

View File

@@ -0,0 +1,71 @@
#include <l4lib/mutex.h>
#include <l4lib/lib/thread.h>
#include <memcache/memcache.h>
/*
* Static stack and utcb for same-space threads.
* +1 is a good approximation for allocating for bitmap
* structures in the memcache.
*/
static char stack[THREADS_TOTAL * (STACK_SIZE + 1)] ALIGN(STACK_SIZE);
static char utcb[THREADS_TOTAL * (UTCB_SIZE + 1)] ALIGN(UTCB_SIZE);
struct mem_cache *utcb_cache;
struct mem_cache *stack_cache;
struct l4_thread_list l4_thread_list;
/* Number of thread structs + allowance for memcache internal data */
#define L4_THREAD_LIST_BUFFER_SIZE (THREADS_TOTAL * \
(sizeof(struct l4_thread_list)) + 256)
static char l4_thread_list_buf[L4_THREAD_LIST_BUFFER_SIZE];
void l4_thread_list_init(void)
{
struct l4_thread_list *tlist = &l4_thread_list;
/* Initialize the head struct */
memset(tlist, 0, sizeof (*tlist));
link_init(&tlist->thread_list);
l4_mutex_init(&tlist->lock);
/* Initialize a cache of l4_thread_list structs */
if (!(tlist->thread_cache =
mem_cache_init(&l4_thread_list_buf,
L4_THREAD_LIST_BUFFER_SIZE,
sizeof(struct l4_thread), 0))) {
printf("FATAL: Could not initialize internal "
"thread struct cache.\n");
BUG();
}
}
void l4_stack_alloc_init(void)
{
BUG_ON(!(stack_cache =
mem_cache_init((void *)stack, STACK_SIZE *
(THREADS_TOTAL + 1),
STACK_SIZE, STACK_SIZE)));
}
/*
* Initialize a memcache that is aligned to utcb size
*/
void l4_utcb_alloc_init(void)
{
BUG_ON(!(utcb_cache =
mem_cache_init((void *)utcb, UTCB_SIZE *
(THREADS_TOTAL + 1),
UTCB_SIZE, UTCB_SIZE)));
}
void __l4_threadlib_init(void)
{
l4_utcb_alloc_init();
l4_stack_alloc_init();
l4_thread_list_init();
l4_parent_thread_init();
}

View File

@@ -0,0 +1,286 @@
/*
* Thread creation userspace helpers
*
* Copyright (C) 2009 - 2010 B Labs Ltd.
*
* Author: Bahadir Balban
*/
#include <l4lib/lib/thread.h>
#include <l4lib/exregs.h>
#include <l4lib/mutex.h>
#include <l4/api/errno.h>
#include <l4/api/thread.h>
#include <memcache/memcache.h>
void *l4_utcb_alloc(void)
{
return mem_cache_alloc(utcb_cache);
}
void l4_utcb_free(void *utcb)
{
BUG_ON(mem_cache_free(utcb_cache, utcb) < 0);
}
void *l4_stack_alloc(void)
{
void *stack = mem_cache_alloc(stack_cache);
/* Since it will grow downwards */
stack += (unsigned long)STACK_SIZE;
return stack;
}
/*
* NOTE: may be unaligned
*/
void l4_stack_free(void *stack)
{
/* Allocation pointer was from beginning of stack */
stack -= (unsigned long)STACK_SIZE;
BUG_ON(mem_cache_free(stack_cache, stack) < 0);
}
/*
* Allocate and init a thread struct for same space
*/
struct l4_thread *l4_thread_init(struct l4_thread *thread)
{
/*
* Allocate stack and utcb
*/
if (!(thread->utcb = l4_utcb_alloc()))
return PTR_ERR(-ENOMEM);
if (!(thread->stack = l4_stack_alloc())) {
l4_utcb_free(thread->utcb);
return PTR_ERR(-ENOMEM);
}
return thread;
}
void l4_thread_free(struct l4_thread *thread)
{
struct l4_thread_list *tlist = &l4_thread_list;
/* Lock the list */
l4_mutex_lock(&tlist->lock);
/* Lock the thread */
l4_mutex_lock(&thread->lock);
/* Remove the thread from its list */
list_remove(&thread->list);
tlist->total--;
/* Unlock list */
l4_mutex_unlock(&tlist->lock);
/* Free thread's stack and utcb if they exist */
if (thread->stack)
l4_stack_free(thread->stack);
if (thread->utcb)
l4_utcb_free(thread->utcb);
/* Free the thread itself */
BUG_ON(mem_cache_free(tlist->thread_cache, thread) < 0);
}
/*
* No locking version
*/
void l4_thread_free_nolock(struct l4_thread *thread)
{
struct l4_thread_list *tlist = &l4_thread_list;
/* Free thread's stack and utcb if they exist */
if (thread->stack)
l4_stack_free(thread->stack);
if (thread->utcb)
l4_utcb_free(thread->utcb);
/* Free the thread itself */
BUG_ON(mem_cache_free(tlist->thread_cache, thread) < 0);
}
/*
* Destroys a child thread and reclaims its
* stack and utcb.
*
* NOTE: This function is to be called with caution:
* The destroyed child must be in a state that will
* not compromise the system integrity, i.e. not holding
* any locks, not in the middle of an operation.
*
* We usually don't know whether a synchronous destruction
* would cause the thread to leave structures prematurely
* (e.g. need to figure out a way of knowing if the thread
* is holding any locks, busy, has children ...)
*/
int thread_destroy(struct l4_thread *thread)
{
struct l4_thread_list *tlist = &l4_thread_list;
int err;
/* Lock the list */
l4_mutex_lock(&tlist->lock);
/* Lock the thread */
l4_mutex_lock(&thread->lock);
/* Remove the thread from its list */
list_remove(&thread->list);
tlist->total--;
/* Unlock list */
l4_mutex_unlock(&tlist->lock);
/* Destroy the thread */
if ((err = l4_thread_control(THREAD_DESTROY, &thread->ids)) < 0)
return err;
/* Reclaim l4_thread structure */
l4_thread_free_nolock(thread);
return 0;
}
struct l4_thread *l4_thread_alloc_init(void)
{
struct l4_thread_list *tlist = &l4_thread_list;
struct l4_thread *thread;
if (!(thread = mem_cache_zalloc(tlist->thread_cache)))
return PTR_ERR(-ENOMEM);
link_init(&thread->list);
l4_mutex_init(&thread->lock);
if (IS_ERR(thread = l4_thread_init(thread))) {
mem_cache_free(tlist->thread_cache, thread);
return PTR_ERR(thread);
}
list_insert(&tlist->thread_list, &thread->list);
tlist->total++;
return thread;
}
/*
* Called during initialization for setting up the
* existing runnable thread
*/
void l4_parent_thread_init(void)
{
struct l4_thread *thread;
struct exregs_data exregs;
int err;
/* Allocate structures for the first thread */
thread = l4_thread_alloc_init();
/* Free the allocated stack since its unnecessary */
l4_stack_free(thread->stack);
/* Read thread ids */
l4_getid(&thread->ids);
/* Set up utcb via exregs */
memset(&exregs, 0, sizeof(exregs));
exregs_set_utcb(&exregs, (unsigned long)thread->utcb);
if ((err = l4_exchange_registers(&exregs,
thread->ids.tid)) < 0) {
printf("FATAL: Initialization of structures for "
"currently runnable thread has failed.\n"
"exregs err=%d\n", err);
l4_thread_free(thread);
}
}
/* For threads to exit on their own without any library maintenance */
void thread_exit(int exit_code)
{
struct task_ids ids;
/* FIXME: Find this from utcb */
l4_getid(&ids);
l4_thread_control(THREAD_DESTROY | exit_code, &ids);
}
int thread_wait(struct l4_thread *thread)
{
int ret;
/* Wait for the thread to exit */
if ((ret = l4_thread_control(THREAD_WAIT, &thread->ids)) < 0)
return ret;
/* Claim its library structures */
l4_thread_free(thread);
/* Return zero or positive thread exit code */
return ret;
}
/*
* Create a new thread in the same address space as caller
*/
int thread_create(int (*func)(void *), void *args, unsigned int flags,
struct l4_thread **tptr)
{
struct exregs_data exregs;
struct l4_thread *thread;
int err;
/* Shared space only */
if (!(TC_SHARE_SPACE & flags)) {
printf("%s: Warning - This function allows only "
"shared space thread creation.\n",
__FUNCTION__);
return -EINVAL;
}
/* Allocate a thread struct */
if (IS_ERR(thread = l4_thread_alloc_init()))
return (int)thread;
/* Assign own space id since TC_SHARE_SPACE requires it */
l4_getid(&thread->ids);
/* Create thread in kernel */
if ((err = l4_thread_control(THREAD_CREATE |
flags, &thread->ids)) < 0)
goto out_err;
/* First word of new stack is arg */
thread->stack[-1] = (unsigned long)args;
/* Second word of new stack is function address */
thread->stack[-2] = (unsigned long)func;
/* Setup new thread pc, sp, utcb */
memset(&exregs, 0, sizeof(exregs));
exregs_set_stack(&exregs, (unsigned long)thread->stack);
exregs_set_utcb(&exregs, (unsigned long)thread->utcb);
exregs_set_pc(&exregs, (unsigned long)setup_new_thread);
if ((err = l4_exchange_registers(&exregs, thread->ids.tid)) < 0)
goto out_err;
/* Start the new thread, unless specified otherwise */
if (!(flags & TC_NOSTART))
if ((err = l4_thread_control(THREAD_RUN,
&thread->ids)) < 0)
goto out_err;
/* Set pointer to thread structure */
*tptr = thread;
return 0;
out_err:
l4_thread_free(thread);
return err;
}

View File

@@ -5,8 +5,8 @@
*/
#include <l4lib/mutex.h>
#include <l4lib/types.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/arch/syslib.h>
#include L4LIB_INC_ARCH(syscalls.h)
#include L4LIB_INC_ARCH(syslib.h)
/*
* NOTES:

View File

@@ -12,28 +12,20 @@ sys.path.append(PROJRELROOT)
from config.projpaths import *
from configure import *
config = configuration_retrieve()
Import('env')
KERNEL_INCLUDE = join(PROJROOT, 'include')
LIBL4_RELDIR = 'conts/libl4'
LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR)
LIBL4_INCLUDE = join(LIBL4_DIR, 'include')
LIBL4_LIBPATH = join(BUILDDIR, LIBL4_RELDIR)
env = Environment(CC = config.user_toolchain + 'gcc',
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding'],
LINKFLAGS = ['-nostdlib'],
ASFLAGS = ['-D__ASSEMBLY__'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc',
CPPPATH = ['.', KERNEL_INCLUDE, LIBL4_INCLUDE],
CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h')
e = env.Clone()
e.Append(CPPPATH = ['include', '.', LIBL4_INCLUDE])
objmm = env.StaticObject(Glob('mm/*.c'))
objmc = env.StaticObject(Glob('memcache/*.[cS]'))
objmalloc = env.StaticObject(Glob('malloc/*.[cS]'))
libmm = env.StaticLibrary('mm', objmm)
libmc = env.StaticLibrary('mc', objmc)
libmalloc = env.StaticLibrary('malloc', objmalloc)
objmm = e.StaticObject(Glob('mm/*.c'))
objmc = e.StaticObject(Glob('memcache/*.[cS]'))
objmalloc = e.StaticObject(Glob('malloc/*.[cS]'))
libmm = e.StaticLibrary('mm', objmm)
libmc = e.StaticLibrary('mc', objmc)
libmalloc = e.StaticLibrary('malloc', objmalloc)
Return('libmm', 'libmc', 'libmalloc')

View File

@@ -10,7 +10,9 @@ PROJRELROOT = '../..'
sys.path.append(PROJRELROOT)
from configure import *
from config.projpaths import *
config = configuration_retrieve()
gcc_arch_flag = config.gcc_arch_flag
headers_root = join(PROJRELROOT, "include/l4")
config_h = join(headers_root, "config.h")
@@ -28,21 +30,24 @@ tests_dir = tests
LIBL4_RELDIR = 'conts/libl4'
LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR)
LIBL4_INCLUDE = join(LIBL4_DIR, 'include')
LIBL4_LIBPATH = join(BUILDDIR, LIBL4_RELDIR)
test_env = Environment(CC = 'gcc -m32',
CCFLAGS = ['-g', '-std=gnu99', '-Wall', '-Werror'],
# This does not work, need to check
test_env = Environment(CC = config.toolchain + 'gcc',
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', \
'-nostdinc', '-Werror', '-march=' + gcc_arch_flag],
ENV = {'PATH' : os.environ['PATH']},
LIBS = ['gcc', 'mm', 'km', 'mc'],
LIBS = ['mm', 'km', 'mc'],
LIBPATH = ['#'],
CPPPATH = ['#include', join(PROJRELROOT, "include"), "#", LIBL4_INCLUDE])
env = Environment(CC = config.user_toolchain + 'gcc',
CCFLAGS = ['-g', '-nostdlib', '-Wall', '-Werror', '-ffreestanding', '-std=gnu99'],
LINKFLAGS = ['-nostdlib'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc',
CPPPATH = [join(PROJRELROOT, "include"), "#", LIBL4_INCLUDE])
env = Environment(CC = config.toolchain + 'gcc',
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', '-std=gnu99', \
'-Wall', '-Werror', '-march=' + gcc_arch_flag],
LINKFLAGS = ['-nostdlib'],
ASFLAGS = ['-D__ASSEMBLY__'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc',
CPPPATH = ['.', join(PROJROOT, 'include'), LIBL4_INCLUDE])
if os.path.exists(config_h) is False:
print "\nThis build requires a valid kernel configuration header."

View File

@@ -179,12 +179,13 @@ struct mem_cache *mem_cache_init(void *start,
unsigned int diff = addr_aligned - addr;
BUG_ON(diff >= struct_size);
if (diff)
total--;
cache_size -= diff;
area_start = addr_aligned;
}
/* Now recalculate total over cache bytes left */
total = cache_size / struct_size;
link_init(&cache->list);
cache->start = area_start;
cache->end = area_start + cache_size;

View File

@@ -9,12 +9,13 @@
#include <l4/macros.h>
#include <l4/types.h>
#include <l4/lib/list.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/arch/syslib.h>
#include "alloc_page.h"
#include INC_GLUE(memory.h)
#include INC_SUBARCH(mm.h)
#include INC_GLUE(memlayout.h)
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(syscalls.h)
#include L4LIB_INC_ARCH(syslib.h)
struct page_allocator allocator;
@@ -95,7 +96,7 @@ void init_page_allocator(unsigned long start, unsigned long end)
link_init(&allocator.pga_cache_list);
/* Initialise the first page area cache */
cache = mem_cache_init(l4_map_helper((void *)start, 1), PAGE_SIZE,
cache = mem_cache_init(phys_to_virt((void *)start), PAGE_SIZE,
sizeof(struct page_area), 0);
list_insert(&cache->list, &allocator.pga_cache_list);
@@ -134,7 +135,6 @@ int check_page_areas(struct page_allocator *p)
{
struct page_area *new;
struct mem_cache *newcache;
void *newpage;
/* If only one free area left */
if (p->pga_free == 1) {
@@ -146,12 +146,9 @@ int check_page_areas(struct page_allocator *p)
/* Free page areas must now be reduced to 0 */
BUG_ON(p->pga_free != 0);
/* Map the new page into virtual memory */
newpage = l4_map_helper((void *)__pfn_to_addr(new->pfn), 1);
/* Initialise it as a new source of page area structures */
newcache = mem_cache_init(newpage, PAGE_SIZE,
sizeof(struct page_area), 0);
newcache = mem_cache_init(phys_to_virt((void *)__pfn_to_addr(new->pfn)),
PAGE_SIZE, sizeof(struct page_area), 0);
/*
* Update the free page area counter
@@ -209,7 +206,12 @@ struct page_area *merge_free_areas(struct page_area *before,
/* Recursively free the cache page */
if (mem_cache_is_empty(c)) {
list_remove(&c->list);
BUG_ON(free_page(l4_unmap_helper(c, 1)) < 0)
if (free_page(virt_to_phys(c)) < 0) {
printf("Page ptr: 0x%lx, virt_to_phys = 0x%lx\n"
"Page not found in cache.\n",
(unsigned long)c, (unsigned long)virt_to_phys(c));
BUG();
}
}
return before;
}

View File

@@ -1,7 +1,7 @@
#ifndef __DEBUG_H__
#define __DEBUG_H__
#include <kmalloc/kmalloc.h>
//#include <kmalloc/kmalloc.h>
#include <mm/alloc_page.h>
#include <l4/lib/list.h>

View File

@@ -10,7 +10,7 @@
#include INC_SUBARCH(mm.h)
#include INC_ARCH(linker.h)
#include INC_PLAT(printascii.h)
#include INC_PLAT(print-early.h)
#include INC_PLAT(offsets.h)
#include INC_GLUE(memlayout.h)

Some files were not shown because too many files have changed in this diff Show More