mirror of
https://github.com/drasko/codezero.git
synced 2026-01-28 02:33:18 +01:00
Kernel updates since December 2009
This commit is contained in:
@@ -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\
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]')
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
|
||||
|
||||
67
conts/baremetal/test_suite/SConstruct
Normal file
67
conts/baremetal/test_suite/SConstruct
Normal 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')
|
||||
21
conts/baremetal/test_suite/container.c
Normal file
21
conts/baremetal/test_suite/container.c
Normal 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();
|
||||
}
|
||||
|
||||
6
conts/baremetal/test_suite/include/capability.h
Normal file
6
conts/baremetal/test_suite/include/capability.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef __CAPABILITY_H__
|
||||
#define __CAPABILITY_H__
|
||||
|
||||
int caps_read_all();
|
||||
|
||||
#endif /* __CAPABILITY_H__ */
|
||||
7
conts/baremetal/test_suite/include/tests.h
Normal file
7
conts/baremetal/test_suite/include/tests.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef __TESTS_H__
|
||||
#define __TESTS_H__
|
||||
|
||||
|
||||
int capability_test(void);
|
||||
|
||||
#endif /* __TESTS_H__ */
|
||||
19
conts/baremetal/test_suite/include/thread.h
Normal file
19
conts/baremetal/test_suite/include/thread.h
Normal 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__ */
|
||||
81
conts/baremetal/test_suite/main.c
Normal file
81
conts/baremetal/test_suite/main.c
Normal 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;
|
||||
}
|
||||
|
||||
11
conts/baremetal/test_suite/src/arch-arm/new_thread.S
Normal file
11
conts/baremetal/test_suite/src/arch-arm/new_thread.S
Normal 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)
|
||||
|
||||
106
conts/baremetal/test_suite/src/capability.c
Normal file
106
conts/baremetal/test_suite/src/capability.c
Normal 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;
|
||||
}
|
||||
|
||||
149
conts/baremetal/test_suite/src/captest.c
Normal file
149
conts/baremetal/test_suite/src/captest.c
Normal 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;
|
||||
}
|
||||
220
conts/baremetal/test_suite/src/example.c
Normal file
220
conts/baremetal/test_suite/src/example.c
Normal 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
|
||||
|
||||
73
conts/baremetal/test_suite/src/thread.c
Normal file
73
conts/baremetal/test_suite/src/thread.c
Normal 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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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 */
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
50
conts/libc/SConstruct
Normal 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)
|
||||
|
||||
@@ -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 *);
|
||||
|
||||
92
conts/libc/include/sys-baremetal/arch-arm/arch/stdint.h
Normal file
92
conts/libc/include/sys-baremetal/arch-arm/arch/stdint.h
Normal 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
60
conts/libc/src/memcpy.S
Normal 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
68
conts/libc/src/memset.S
Normal 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)
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
31
conts/libc/src/sys-userspace/arch-arm/sys_getc.c
Normal file
31
conts/libc/src/sys-userspace/arch-arm/sys_getc.c
Normal 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;
|
||||
}
|
||||
@@ -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
51
conts/libdev/SConstruct
Normal 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)
|
||||
|
||||
12
conts/libdev/include/libdev/io.h
Normal file
12
conts/libdev/include/libdev/io.h
Normal 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__ */
|
||||
23
conts/libdev/include/libdev/timer.h
Normal file
23
conts/libdev/include/libdev/timer.h
Normal 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__ */
|
||||
21
conts/libdev/include/libdev/uart.h
Normal file
21
conts/libdev/include/libdev/uart.h
Normal 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__ */
|
||||
15
conts/libdev/timer/omap/SConscript
Normal file
15
conts/libdev/timer/omap/SConscript
Normal 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')
|
||||
97
conts/libdev/timer/omap/timer.c
Normal file
97
conts/libdev/timer/omap/timer.c
Normal 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);
|
||||
}
|
||||
51
conts/libdev/timer/omap/timer.h
Normal file
51
conts/libdev/timer/omap/timer.h
Normal 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__*/
|
||||
14
conts/libdev/timer/sp804/SConscript
Normal file
14
conts/libdev/timer/sp804/SConscript
Normal 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')
|
||||
65
conts/libdev/timer/sp804/timer.c
Normal file
65
conts/libdev/timer/sp804/timer.c
Normal 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);
|
||||
}
|
||||
63
conts/libdev/timer/sp804/timer.h
Normal file
63
conts/libdev/timer/sp804/timer.h
Normal 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__ */
|
||||
15
conts/libdev/uart/omap/SConscript
Normal file
15
conts/libdev/uart/omap/SConscript
Normal 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')
|
||||
115
conts/libdev/uart/omap/uart.c
Normal file
115
conts/libdev/uart/omap/uart.c
Normal 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
|
||||
}
|
||||
|
||||
|
||||
195
conts/libdev/uart/omap/uart.h
Normal file
195
conts/libdev/uart/omap/uart.h
Normal 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__ */
|
||||
14
conts/libdev/uart/pl011/SConscript
Normal file
14
conts/libdev/uart/pl011/SConscript
Normal 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')
|
||||
127
conts/libdev/uart/pl011/uart.c
Normal file
127
conts/libdev/uart/pl011/uart.c
Normal 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
|
||||
}
|
||||
|
||||
252
conts/libdev/uart/pl011/uart.h
Normal file
252
conts/libdev/uart/pl011/uart.h
Normal 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__ */
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
15
conts/libl4/include/l4lib/arch/arm/asm.h
Normal file
15
conts/libl4/include/l4lib/arch/arm/asm.h
Normal 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__ */
|
||||
|
||||
11
conts/libl4/include/l4lib/arch/arm/irq.h
Normal file
11
conts/libl4/include/l4lib/arch/arm/irq.h
Normal 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
|
||||
95
conts/libl4/include/l4lib/arch/arm/syscalls.h
Normal file
95
conts/libl4/include/l4lib/arch/arm/syscalls.h
Normal 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__ */
|
||||
|
||||
366
conts/libl4/include/l4lib/arch/arm/syslib.h
Normal file
366
conts/libl4/include/l4lib/arch/arm/syslib.h
Normal 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__ */
|
||||
8
conts/libl4/include/l4lib/arch/arm/types.h
Normal file
8
conts/libl4/include/l4lib/arch/arm/types.h
Normal 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__ */
|
||||
78
conts/libl4/include/l4lib/arch/arm/utcb.h
Normal file
78
conts/libl4/include/l4lib/arch/arm/utcb.h
Normal 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__ */
|
||||
3
conts/libl4/include/l4lib/arch/arm/v5/perfmon.h
Normal file
3
conts/libl4/include/l4lib/arch/arm/v5/perfmon.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#ifndef __PERFMON_H__
|
||||
|
||||
#endif
|
||||
21
conts/libl4/include/l4lib/arch/arm/v5/utcb.h
Normal file
21
conts/libl4/include/l4lib/arch/arm/v5/utcb.h
Normal 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__ */
|
||||
405
conts/libl4/include/l4lib/arch/arm/v7/perfmon.h
Normal file
405
conts/libl4/include/l4lib/arch/arm/v7/perfmon.h
Normal 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__ */
|
||||
|
||||
59
conts/libl4/include/l4lib/arch/arm/v7/utcb.h
Normal file
59
conts/libl4/include/l4lib/arch/arm/v7/utcb.h
Normal 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__ */
|
||||
13
conts/libl4/include/l4lib/cache.h
Normal file
13
conts/libl4/include/l4lib/cache.h
Normal 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__ */
|
||||
@@ -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)
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
27
conts/libl4/include/l4lib/lib/addr.h
Normal file
27
conts/libl4/include/l4lib/lib/addr.h
Normal 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__ */
|
||||
44
conts/libl4/include/l4lib/lib/bit.h
Normal file
44
conts/libl4/include/l4lib/lib/bit.h
Normal 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__ */
|
||||
75
conts/libl4/include/l4lib/lib/cap.h
Normal file
75
conts/libl4/include/l4lib/lib/cap.h
Normal 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__ */
|
||||
32
conts/libl4/include/l4lib/lib/idpool.h
Normal file
32
conts/libl4/include/l4lib/lib/idpool.h
Normal 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__ */
|
||||
65
conts/libl4/include/l4lib/lib/thread.h
Normal file
65
conts/libl4/include/l4lib/lib/thread.h
Normal 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__ */
|
||||
25
conts/libl4/include/l4lib/macros.h
Normal file
25
conts/libl4/include/l4lib/macros.h
Normal 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__ */
|
||||
13
conts/libl4/include/l4lib/perfmon.h
Normal file
13
conts/libl4/include/l4lib/perfmon.h
Normal 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
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
99
conts/libl4/src/arch/arm/exregs.c
Normal file
99
conts/libl4/src/arch/arm/exregs.c
Normal 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);
|
||||
}
|
||||
|
||||
21
conts/libl4/src/arch/arm/new_thread.S
Normal file
21
conts/libl4/src/arch/arm/new_thread.S
Normal 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)
|
||||
|
||||
235
conts/libl4/src/arch/arm/syscalls.S
Normal file
235
conts/libl4/src/arch/arm/syscalls.S
Normal 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)
|
||||
103
conts/libl4/src/arch/arm/v5/mutex.c
Normal file
103
conts/libl4/src/arch/arm/v5/mutex.c
Normal 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;
|
||||
|
||||
}
|
||||
97
conts/libl4/src/arch/arm/v6/mutex.c
Normal file
97
conts/libl4/src/arch/arm/v6/mutex.c
Normal 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;
|
||||
}
|
||||
48
conts/libl4/src/arch/arm/v7/mutex.S
Normal file
48
conts/libl4/src/arch/arm/v7/mutex.S
Normal 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)
|
||||
|
||||
|
||||
45
conts/libl4/src/arch/arm/v7/perfmon.c
Normal file
45
conts/libl4/src/arch/arm/v7/perfmon.c
Normal 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 */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
62
conts/libl4/src/lib/addr.c
Normal file
62
conts/libl4/src/lib/addr.c
Normal 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
109
conts/libl4/src/lib/bit.c
Normal 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;
|
||||
}
|
||||
|
||||
179
conts/libl4/src/lib/cap/cap.c
Normal file
179
conts/libl4/src/lib/cap/cap.c
Normal 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");
|
||||
}
|
||||
|
||||
|
||||
1
conts/libl4/src/lib/cap/read.c
Normal file
1
conts/libl4/src/lib/cap/read.c
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
93
conts/libl4/src/lib/idpool.c
Normal file
93
conts/libl4/src/lib/idpool.c
Normal 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;
|
||||
}
|
||||
|
||||
71
conts/libl4/src/lib/thread/init.c
Normal file
71
conts/libl4/src/lib/thread/init.c
Normal 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();
|
||||
}
|
||||
|
||||
286
conts/libl4/src/lib/thread/thread.c
Normal file
286
conts/libl4/src/lib/thread/thread.c
Normal 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;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user