mirror of
https://github.com/drasko/codezero.git
synced 2026-10-25 03:07:28 +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 @@
|
||||
|
||||
|
||||
|
||||
@@ -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')
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef __CAPABILITY_H__
|
||||
#define __CAPABILITY_H__
|
||||
|
||||
int caps_read_all();
|
||||
|
||||
#endif /* __CAPABILITY_H__ */
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef __TESTS_H__
|
||||
#define __TESTS_H__
|
||||
|
||||
|
||||
int capability_test(void);
|
||||
|
||||
#endif /* __TESTS_H__ */
|
||||
@@ -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__ */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
arch-arm
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user