1. Old pending files cleaned from public repo. 2. Thread_create routines removed from timer_service and kmi_service. 3. Sconstruct of libdev updated.

This commit is contained in:
Amit Mahajan
2010-03-30 14:44:05 +05:30
parent 92645be6ff
commit 2b340c9f2f
86 changed files with 27 additions and 7113 deletions

View File

@@ -1,67 +0,0 @@
# -*- 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 *
config = configuration_retrieve()
platform = config.platform
arch = config.arch
gcc_cpu_flag = config.gcc_cpu_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'),
join(LIBDEV_DIR, 'clcd/pl110/include')]
LIBDEV_CCFLAGS = '-DPLATFORM_' + platform.upper()
# FIXME: Add these to autogenerated SConstruct !!!
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',
# 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],
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.
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]')
objs = env.Object(src)
prog = env.Program('main.elf', objs)
Depends(prog, 'include/linker.lds')

View File

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

View File

@@ -1,13 +0,0 @@
/*
* Autogenerated definitions for this container.
*/
#ifndef __CONTAINER_H__
#define __CONTAINER_H__
#define __CONTAINER_NAME__ "uart_service"
#define __CONTAINER_ID__ 0
#define __CONTAINER__ "cont0"
#endif /* __CONTAINER_H__ */

View File

@@ -1,7 +0,0 @@
#ifndef __LINKER_H__
#define __LINKER_H__
extern char vma_start[];
extern char __end[];
#endif /* __LINKER_H__ */

View File

@@ -1,277 +0,0 @@
/*
* CLCD service for userspace
*/
#include <l4lib/arch/syslib.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/addr.h>
#include <l4lib/exregs.h>
#include <l4lib/ipcdefs.h>
#include <l4/api/errno.h>
#include <l4/api/space.h>
#include <l4lib/capability/cap_print.h>
#include <container.h>
#include <pl110_clcd.h> /* FIXME: Its best if this is <libdev/uart/pl011.h> */
#include <linker.h>
#define CLCD_TOTAL 1
static struct capability caparray[32];
static int total_caps = 0;
struct capability clcd_cap[CLCD_TOTAL];
int cap_read_all()
{
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();
}
total_caps = ncaps;
/* Read all capabilities */
if ((err = l4_capability_control(CAP_CONTROL_READ,
0, caparray)) < 0) {
printf("l4_capability_control() reading of "
"capabilities failed.\n Could not "
"complete CAP_CONTROL_READ_CAPS request.\n");
BUG();
}
return 0;
}
/*
* Scans for up to CLCD_TOTAL clcd devices in capabilities.
*/
int clcd_probe_devices(void)
{
int clcds = 0;
/* Scan for clcd devices */
for (int i = 0; i < total_caps; i++) {
/* Match device type */
if (cap_devtype(&caparray[i]) == CAP_DEVTYPE_CLCD) {
/* Copy to correct device index */
memcpy(&clcd_cap[cap_devnum(&caparray[i])],
&caparray[i], sizeof(clcd_cap[0]));
clcds++;
}
}
if (clcds != CLCD_TOTAL) {
printf("%s: Error, not all clcd could be found. "
"total clcds=%d\n", __CONTAINER_NAME__, clcds);
return -ENODEV;
}
return 0;
}
/*
* 1MB frame buffer,
* FIXME: can we do dma in this buffer?
*/
#define CLCD_FRAMEBUFFER_SZ 0x100000
static char framebuffer[CLCD_FRAMEBUFFER_SZ];
static struct pl110_clcd clcd[CLCD_TOTAL];
int clcd_setup_devices(void)
{
for (int i = 0; i < CLCD_TOTAL; i++) {
/* Get one page from address pool */
clcd[i].virt_base = (unsigned long)l4_new_virtual(1);
/* Map clcd to a virtual address region */
if (IS_ERR(l4_map((void *)__pfn_to_addr(clcd_cap[i].start),
(void *)clcd[i].virt_base, clcd_cap[i].size,
MAP_USR_IO_FLAGS,
self_tid()))) {
printf("%s: FATAL: Failed to map CLCD device "
"%d to a virtual address\n",
__CONTAINER_NAME__,
cap_devnum(&clcd_cap[i]));
BUG();
}
/* Initialize clcd */
pl110_initialise(&clcd[i], framebuffer);
}
return 0;
}
static struct address_pool device_vaddr_pool;
/*
* Initialize a virtual address pool
* for mapping physical devices.
*/
void init_vaddr_pool(void)
{
for (int i = 0; i < total_caps; i++) {
/* Find the virtual memory region for this process */
if (cap_type(&caparray[i]) == CAP_TYPE_MAP_VIRTMEM &&
__pfn_to_addr(caparray[i].start) ==
(unsigned long)vma_start) {
/*
* Do we have any unused virtual space
* where we run, and do we have enough
* pages of it to map all clcd?
*/
if (__pfn(page_align_up(__end))
+ CLCD_TOTAL <= caparray[i].end) {
/*
* Yes. We initialize the device
* virtual memory pool here.
*
* We may allocate virtual memory
* addresses from this pool.
*/
address_pool_init(&device_vaddr_pool,
page_align_up(__end),
__pfn_to_addr(caparray[i].end),
CLCD_TOTAL);
return;
} else
goto out_err;
}
}
out_err:
printf("%s: FATAL: No virtual memory "
"region available to map "
"devices.\n", __CONTAINER_NAME__);
BUG();
}
void *l4_new_virtual(int npages)
{
return address_new(&device_vaddr_pool, npages, PAGE_SIZE);
}
void handle_requests(void)
{
u32 mr[MR_UNUSED_TOTAL];
l4id_t senderid;
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);
BUG();
}
/* Syslib conventional ipc data which uses first few mrs. */
tag = l4_get_tag();
senderid = l4_get_sender();
/* Read mrs not used by syslib */
for (int i = 0; i < MR_UNUSED_TOTAL; i++)
mr[i] = read_mr(MR_UNUSED_START + i);
/*
* TODO:
*
* Maybe add tags here that handle requests for sharing
* of the requested cld device with the client?
*
* In order to be able to do that, we should have a
* shareable/grantable capability to the device. Also
* the request should (currently) come from a task
* inside the current container
*/
/*
* FIXME: Right now we are talking to CLCD by default, we need to define protocol
* for sommunication with CLCD service
*/
switch (tag) {
default:
printf("%s: Error received ipc from 0x%x residing "
"in container %x with an unrecognized tag: "
"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();
}
}
/*
* UTCB-size aligned utcb.
*
* BIG WARNING NOTE:
* This in-place declaration is legal if we are running
* in a disjoint virtual address space, where the utcb
* declaration lies in a unique virtual address in
* the system.
*/
#define DECLARE_UTCB(name) \
struct utcb name ALIGN(sizeof(struct utcb))
DECLARE_UTCB(utcb);
/* Set up own utcb for ipc */
int l4_utcb_setup(void *utcb_address)
{
struct task_ids ids;
struct exregs_data exregs;
int err;
l4_getid(&ids);
/* Clear utcb */
memset(utcb_address, 0, sizeof(struct utcb));
/* Setup exregs for utcb request */
memset(&exregs, 0, sizeof(exregs));
exregs_set_utcb(&exregs, (unsigned long)utcb_address);
if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0)
return err;
return 0;
}
void main(void)
{
int err;
/* Read all capabilities */
cap_read_all();
/* Scan for clcd devices in capabilities */
clcd_probe_devices();
/* Initialize virtual address pool for clcds */
init_vaddr_pool();
/* Map and initialize clcd devices */
clcd_setup_devices();
/* Setup own utcb */
if ((err = l4_utcb_setup(&utcb)) < 0) {
printf("FATAL: Could not set up own utcb. "
"err=%d\n", err);
BUG();
}
/* Listen for clcd requests */
while (1)
handle_requests();
}

View File

@@ -6,7 +6,7 @@
#include <l4lib/init.h>
#include <l4lib/utcb.h>
#include <l4lib/lib/thread.h>
void main(void);
@@ -15,6 +15,9 @@ void __container_init(void)
/* Generic L4 initialisation */
__l4_init();
/* Thread library initialisation */
__l4_threadlib_init();
/* Entry to main */
main();
}

View File

@@ -4,10 +4,6 @@
#ifndef __MOUSE_H__
#define __MOUSE_H__
#include <l4lib/mutex.h>
#include <l4/lib/list.h>
#include <l4lib/types.h>
/*
* Keyboard structure
*/

View File

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

View File

@@ -2,6 +2,7 @@
* Keyboard and Mouse service for userspace
*/
#include <l4lib/lib/addr.h>
#include <l4lib/lib/thread.h>
#include <l4lib/irq.h>
#include <l4lib/ipcdefs.h>
#include <l4/api/errno.h>
@@ -14,7 +15,6 @@
#include <linker.h>
#include <keyboard.h>
#include <mouse.h>
#include <thread.h>
#define KEYBOARDS_TOTAL 1
#define MOUSE_TOTAL 1
@@ -179,7 +179,8 @@ int mouse_irq_handler(void *arg)
int kmi_setup_devices(void)
{
struct task_ids irq_tids;
struct l4_thread thread;
struct l4_thread *tptr = &thread;
int err;
for (int i = 0; i < KEYBOARDS_TOTAL; i++) {
@@ -209,7 +210,7 @@ int kmi_setup_devices(void)
*/
if ((err = thread_create(keyboard_irq_handler, &kbd[i],
TC_SHARE_SPACE,
&irq_tids)) < 0) {
&tptr)) < 0) {
printf("FATAL: Creation of irq handler "
"thread failed.\n");
BUG();
@@ -238,7 +239,7 @@ int kmi_setup_devices(void)
* wait on irqs.
*/
if ((err = thread_create(mouse_irq_handler, &mouse[i],
TC_SHARE_SPACE, &irq_tids)) < 0) {
TC_SHARE_SPACE, &tptr)) < 0) {
printf("FATAL: Creation of irq handler "
"thread failed.\n");
BUG();

View File

@@ -1,11 +0,0 @@
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(asm.h)
BEGIN_PROC(local_setup_new_thread)
ldr r0, [sp, #-4]! @ Load first argument.
mov lr, pc @ Save return address
ldr pc, [sp, #-4]! @ Load function pointer from stack
new_thread_exit:
b new_thread_exit @ We infinitely loop for now.
END_PROC(local_setup_new_thread)

View File

@@ -1,73 +0,0 @@
/*
* 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 long *)__stack_ptr)[-1] = (unsigned long)args;
/* Second word of new stack is function address */
((unsigned long *)__stack_ptr)[-2] = (unsigned long)func;
/* Setup new thread pc, sp, utcb */
memset(&exregs, 0, sizeof(exregs));
exregs_set_stack(&exregs, (unsigned long)__stack_ptr);
exregs_set_utcb(&exregs, (unsigned long)__utcb_ptr);
exregs_set_pc(&exregs, (unsigned long)local_setup_new_thread);
if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0)
return err;
/* Update utcb, stack pointers */
__stack_ptr += STACK_SIZE;
__utcb_ptr += UTCB_SIZE;
/* Start the new thread */
if ((err = l4_thread_control(THREAD_RUN, &ids)) < 0)
return err;
memcpy(new_ids, &ids, sizeof(ids));
return 0;
}

View File

@@ -1,68 +0,0 @@
# -*- 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_cpu_flag = config.gcc_cpu_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')]
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',
# 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],
LINKFLAGS = ['-nostdlib', '-T' + "include/linker.lds", "-u_start"],\
ASFLAGS = ['-D__ASSEMBLY__'], \
PROGSUFFIX = '.elf', # The suffix to use for final executable\
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path\
LIBS = ['gcc', 'libl4', 'c-userspace', 'libdev-userspace', 'gcc', 'libmalloc',
'c-userspace'], # libgcc.a - This is required for division routines.
CPPPATH = ["#include", KERNEL_INCLUDE, LIBL4_INCLUDE, LIBDEV_INCLUDE, LIBC_INCLUDE, LIBMEM_INCLUDE],
LIBPATH = [LIBL4_LIBPATH, LIBDEV_LIBPATH, LIBC_LIBPATH, LIBMEM_LIBPATH],
CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h')
src = Glob('*.[cS]')
src += Glob('src/*.[cS]')
src += Glob('src/arch/*.[cS]')
objs = env.Object(src)
prog = env.Program('main.elf', objs)
Depends(prog, 'include/linker.lds')

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1 +0,0 @@
arch-arm

View File

@@ -1,11 +0,0 @@
#include <l4lib/arch/asm.h>
BEGIN_PROC(local_setup_new_thread)
ldr r0, [sp, #-4]! @ Load first argument.
mov lr, pc @ Save return address
ldr pc, [sp, #-4]! @ Load function pointer from stack
new_thread_exit:
b new_thread_exit @ We infinitely loop for now.
END_PROC(local_setup_new_thread)

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@
#include <l4lib/init.h>
#include <l4lib/utcb.h>
#include <l4lib/lib/thread.h>
void main(void);
@@ -15,6 +15,9 @@ void __container_init(void)
/* Generic L4 initialisation */
__l4_init();
/* Thread library initialisation */
__l4_threadlib_init();
/* Entry to main */
main();
}

View File

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

View File

@@ -3,6 +3,7 @@
*/
#include <l4lib/lib/addr.h>
#include <l4lib/irq.h>
#include <l4lib/lib/thread.h>
#include <l4lib/ipcdefs.h>
#include <l4/api/errno.h>
#include <l4/api/irq.h>
@@ -13,7 +14,6 @@
#include <container.h>
#include <linker.h>
#include <timer.h>
#include <thread.h>
#include <libdev/timer.h>
/* Capabilities of this service */
@@ -296,7 +296,8 @@ void task_wake(void)
int timer_setup_devices(void)
{
struct task_ids irq_tids;
struct l4_thread thread;
struct l4_thread *tptr = &thread;
int err;
for (int i = 0; i < TIMERS_TOTAL; i++) {
@@ -324,7 +325,7 @@ int timer_setup_devices(void)
*/
if ((err = thread_create(timer_irq_handler, &timer[i],
TC_SHARE_SPACE,
&irq_tids)) < 0) {
&tptr)) < 0) {
printf("FATAL: Creation of irq handler "
"thread failed.\n");
BUG();

View File

@@ -1,11 +0,0 @@
#include <l4lib/macros.h>
#include L4LIB_INC_ARCH(asm.h)
BEGIN_PROC(local_setup_new_thread)
ldr r0, [sp, #-4]! @ Load first argument.
mov lr, pc @ Save return address
ldr pc, [sp, #-4]! @ Load function pointer from stack
new_thread_exit:
b new_thread_exit @ We infinitely loop for now.
END_PROC(local_setup_new_thread)

View File

@@ -1,75 +0,0 @@
/*
* 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[THREADS_TOTAL][0x1000] ALIGN(0x1000);
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: Warning - 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 long *)__stack_ptr)[-1] = (unsigned long)args;
/* Second word of new stack is function address */
((unsigned long *)__stack_ptr)[-2] = (unsigned long)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;
//__utcb_ptr += 0x1000;
/* Start the new thread */
if ((err = l4_thread_control(THREAD_RUN, &ids)) < 0)
return err;
memcpy(new_ids, &ids, sizeof(ids));
return 0;
}

View File

@@ -46,6 +46,12 @@ objects += SConscript('uart/pl011/SConscript', duplicate=0, \
exports = {'platform' : platform, 'env' : env})
objects += SConscript('timer/sp804/SConscript', duplicate=0, \
exports = {'platform' : platform, 'env' : env})
objects += SConscript('kmi/pl050/SConscript', duplicate=0, \
exports = {'platform' : platform, 'env' : env})
objects += SConscript('uart/omap/SConscript', duplicate=0, \
exports = {'platform' : platform, 'env' : env})
objects += SConscript('timer/omap/SConscript', duplicate=0, \
exports = {'platform' : platform, 'env' : env})
library = env.StaticLibrary('libdev-' + variant, objects)

View File

@@ -1,104 +0,0 @@
#ifndef __PL110_CLCD_H__
#define __PL110_CLCD_H__
/* Register offsets */
#define PL110_CLCD_TIMING0 0x000 /* Horizontal Axis Panel Control*/
#define PL110_CLCD_TIMING1 0x004 /* Vertical Axis Panel Control */
#define PL110_CLCD_TIMING2 0x008 /* Clock and Polarity Signal Control*/
#define PL110_CLCD_TIMING3 0x00c /* Line End Control */
#define PL110_CLCD_UPBASE 0x010 /* Upper Panel Frame Base Address*/
#define PL110_CLCD_LPBASE 0x014 /* Lower Panel Frame Base Address */
#define PL110_CLCD_IMSC 0x018 /* Interrupt Mast Set Clear */
#define PL110_CLCD_CONTROL 0x01c /* CLCD Control */
#define PL110_CLCD_RIS 0x020 /* Raw Interrupt Status */
#define PL110_CLCD_MIS 0x024 /* Masked Interrupt Status */
#define PL110_CLCD_ICR 0x028 /* Interrupt Clear */
#define PL110_CLCD_UPCURR 0x02c /* Upper Panel Current Address Value */
#define PL110_CLCD_LPCURR 0x030 /* Lower Panel Current Address Value */
//#define PL110_LCD_PALETTE
#define PL110_CLCD_PERIPHID0 0xfe0 /* Peripheral Identification */
#define PL110_CLCD_PERIPHID1 0xfe4 /* Peripheral Identification */
#define PL110_CLCD_PERIPHID2 0xfe8 /* Peripheral Identification */
#define PL110_CLCD_PERIPHID3 0xfec /* Peripheral Identification */
#define PL110_CLCD_PCELLID0 0xff0 /* Peripheral Identification */
#define PL110_CLCD_PCELLID1 0xff4 /* PrimeCell Identification */
#define PL110_CLCD_PCELLID2 0xff8 /* PrimeCell Identification */
#define PL110_CLCD_PCELLID3 0xffc /* PrimeCell Identification */
/* Scan mode */
#define SCAN_VMODE_NONINTERLACED 0 /* non interlaced */
#define SCAN_VMODE_INTERLACED 1 /* interlaced */
#define SCAN_VMODE_DOUBLE 2 /* double scan */
#define SCAN_VMODE_ODD_FLD_FIRST 4 /* interlaced: top line first */
#define SCAN_VMODE_MASK 255
/* Control Register Bits */
#define PL110_CNTL_LCDEN (1 << 0)
#define PL110_CNTL_LCDBPP1 (0 << 1)
#define PL110_CNTL_LCDBPP2 (1 << 1)
#define PL110_CNTL_LCDBPP4 (2 << 1)
#define PL110_CNTL_LCDBPP8 (3 << 1)
#define PL110_CNTL_LCDBPP16 (4 << 1)
#define PL110_CNTL_LCDBPP16_565 (6 << 1)
#define PL110_CNTL_LCDBPP24 (5 << 1)
#define PL110_CNTL_LCDBW (1 << 4)
#define PL110_CNTL_LCDTFT (1 << 5)
#define PL110_CNTL_LCDMONO8 (1 << 6)
#define PL110_CNTL_LCDDUAL (1 << 7)
#define PL110_CNTL_BGR (1 << 8)
#define PL110_CNTL_BEBO (1 << 9)
#define PL110_CNTL_BEPO (1 << 10)
#define PL110_CNTL_LCDPWR (1 << 11)
#define PL110_CNTL_LCDVCOMP(x) ((x) << 12)
#define PL110_CNTL_LDMAFIFOTIME (1 << 15)
#define PL110_CNTL_WATERMARK (1 << 16)
#define PL110_TIM2_CLKSEL (1 << 5)
#define PL110_TIM2_IVS (1 << 11)
#define PL110_TIM2_IHS (1 << 12)
#define PL110_TIM2_IPC (1 << 13)
#define PL110_TIM2_IOE (1 << 14)
#define PL110_TIM2_BCD (1 << 26)
struct videomode {
const char *name; /* optional */
unsigned int refresh; /* optional */
unsigned int xres;
unsigned int yres;
unsigned int pixclock;
unsigned int left_margin;
unsigned int right_margin;
unsigned int upper_margin;
unsigned int lower_margin;
unsigned int hsync_len;
unsigned int vsync_len;
unsigned int sync;
unsigned int vmode;
unsigned int flag;
};
struct pl110_clcd_panel {
struct videomode mode;
signed short width; /* width in mm */
signed short height; /* height in mm */
unsigned int tim2;
unsigned int tim3;
unsigned int cntl;
unsigned int bpp:8,
fixedtimings:1,
grayscale:1;
unsigned int connector;
};
struct pl110_clcd {
unsigned int virt_base;
struct pl110_clcd_panel *panel;
char *frame_buffer;
};
void pl110_initialise(struct pl110_clcd *clcd, char *buf);
#endif /* __PL110_CLCD_H__ */

View File

@@ -1,68 +0,0 @@
#include <pl110_clcd.h>
#define read(a) *((volatile unsigned int *)(a))
#define write(v, a) (*((volatile unsigned int *)(a)) = v)
#define setbit(bit, a) write(read(a) | bit, a)
#define clrbit(bit, a) write(read(a) & ~bit, a)
/*
* Default panel, we will use this for now
* Seems like qemu has support for this
*/
static struct pl110_clcd_panel vga = {
.mode = {
.name = "VGA",
.refresh = 60,
.xres = 640,
.yres = 480,
.pixclock = 39721,
.left_margin = 40,
.right_margin = 24,
.upper_margin = 32,
.lower_margin = 11,
.hsync_len = 96,
.vsync_len = 2,
.sync = 0,
.vmode = SCAN_VMODE_NONINTERLACED,
},
.width = -1,
.height = -1,
.tim2 = PL110_TIM2_BCD | PL110_TIM2_IPC,
.cntl = PL110_CNTL_LCDTFT | PL110_CNTL_LCDVCOMP(1),
.bpp = 16,
};
static void pl110_clcd_set_uppanel_fb(unsigned int clcd_base,
unsigned int fb_base)
{
write(fb_base, (clcd_base + PL110_CLCD_UPBASE));
}
#if 0
static void pl110_clcd_set_lwrpanel_fb(unsigned int clcd_base, unsigned int fb_base)
{
write(fb_base, (clcd_base +PL110_CLCD_LPBASE));
}
static unsigned int pl110_clcd_get_uppanel_fb(unsigned int clcd_base)
{
return read((clcd_base +PL110_CLCD_UPBASE));
}
static unsigned int pl110_clcd_get_lwrpanel_fb(unsigned int clcd_base)
{
return read((clcd_base +PL110_CLCD_LPBASE));
}
#endif
void pl110_initialise(struct pl110_clcd *clcd, char *buf)
{
clcd->panel = &vga;
clcd->frame_buffer = buf;
pl110_clcd_set_uppanel_fb(clcd->virt_base, (unsigned int)(buf));
}

View File

@@ -1,67 +0,0 @@
/*
* SP804 Primecell Timer offsets
*
* Copyright (C) 2007 Bahadir Balban
*
*/
#ifndef __SP804_TIMER_H__
#define __SP804_TIMER_H__
#define SP804_TIMER2_OFFSET 0x20
/* Base address of Timers for differen platforms */
#if defined(PLATFORM_PB926)
#define TIMER0_PHYS_BASE 0x101E2000
#define TIMER1_PHYS_BASE (TIMER0_PHYS_BASE + SP804_TIMER2_OFFSET)
#define TIMER2_PHYS_BASE 0x101E3000
#define TIMER3_PHYS_BASE (TIMER2_PHYS_BASE + SP804_TIMER2_OFFSET)
#elif defined(PLATFORM_EB)
#define TIMER0_PHYS_BASE 0x10011000
#define TIMER1_PHYS_BASE (TIMER0_PHYS_BASE + SP804_TIMER2_OFFSET)
#define TIMER2_PHYS_BASE 0x10012000
#define TIMER3_PHYS_BASE (TIMER2_PHYS_BASE + SP804_TIMER2_OFFSET)
#elif defined(PLATFORM_PB11MPCORE)
#define TIMER0_PHYS_BASE 0x10011000
#define TIMER1_PHYS_BASE (TIMER0_PHYS_BASE + SP804_TIMER2_OFFSET)
#define TIMER2_PHYS_BASE 0x10012000
#define TIMER3_PHYS_BASE (TIMER2_PHYS_BASE + SP804_TIMER2_OFFSET)
#define TIMER4_PHYS_BASE 0x10018000
#define TIMER5_PHYS_BASE (TIMER4_PHYS_BASE + SP804_TIMER2_OFFSET)
#define TIMER6_PHYS_BASE 0x10019000
#define TIMER7_PHYS_BASE (TIMER6_PHYS_BASE + SP804_TIMER2_OFFSET)
#endif
/* Run mode of timers */
#define SP804_TIMER_RUNMODE_FREERUN 0
#define SP804_TIMER_RUNMODE_PERIODIC 1
/* Wrap mode of timers */
#define SP804_TIMER_WRAPMODE_WRAPPING 0
#define SP804_TIMER_WRAPMODE_ONESHOT 1
/* Operational width of timer */
#define SP804_TIMER_WIDTH16BIT 0
#define SP804_TIMER_WIDTH32BIT 1
/* Enable/disable irq on timer */
#define SP804_TIMER_IRQDISABLE 0
#define SP804_TIMER_IRQENABLE 1
/* Register offsets */
#define SP804_TIMERLOAD 0x0
#define SP804_TIMERVALUE 0x4
#define SP804_TIMERCONTROL 0x8
#define SP804_TIMERINTCLR 0xC
#define SP804_TIMERRIS 0x10
#define SP804_TIMERMIS 0x14
#define SP804_TIMERBGLOAD 0x18
void sp804_init(unsigned int timer_base, int runmode, int wrapmode, \
int width, int irq_enable);
void sp804_irq_handler(unsigned int timer_base);
void sp804_enable(unsigned int timer_base, int enable);
void sp804_set_irq(unsigned int timer_base, int enable);
unsigned int sp804_read_value(unsigned int timer_base);
#endif /* __SP804_TIMER_H__ */

View File

@@ -1,107 +0,0 @@
/*
* SP804 Primecell Timer driver
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <sp804_timer.h>
#define read(a) *((volatile unsigned int *)(a))
#define write(v, a) (*((volatile unsigned int *)(a)) = v)
#define setbit(bit, a) write(read(a) | bit, a)
#define clrbit(bit, a) write(read(a) & ~bit, a)
extern void timer_irq_handler(void);
void sp804_irq_handler(unsigned int timer_base)
{
/*
* Timer enabled as Periodic/Wrapper only needs irq clearing
* as it automatically reloads and wraps
*/
write(1, (timer_base + SP804_TIMERINTCLR));
timer_irq_handler();
}
static inline void sp804_control(unsigned int timer_base, int bit, int setclr)
{
unsigned long addr = (timer_base + SP804_TIMERCONTROL);
setclr ? setbit(bit, addr) : clrbit(bit, addr);
}
/*
* Sets timer's run mode:
* @periodic: periodic mode = 1, free-running = 0.
*/
#define SP804_PEREN (1 << 6)
static inline void sp804_set_runmode(unsigned int timer_base, int periodic)
{
sp804_control(timer_base, SP804_PEREN, periodic);
}
/*
* Sets timer's wrapping mode:
* @oneshot: oneshot = 1, wrapping = 0.
*/
#define SP804_ONESHOT (1 << 0)
static inline void sp804_set_wrapmode(unsigned int timer_base, int oneshot)
{
sp804_control(timer_base, SP804_ONESHOT, oneshot);
}
/*
* Sets the operational width of timers.
* In 16bit mode, top halfword is ignored.
* @width: 32bit mode = 1; 16bit mode = 0
*/
#define SP804_32BIT (1 << 1)
static inline void sp804_set_widthmode(unsigned int timer_base, int width)
{
sp804_control(timer_base, SP804_32BIT, width);
}
/*
* Enable/disable timer:
* @enable: enable = 1, disable = 0;
*/
#define SP804_ENABLE (1 << 7)
void sp804_enable(unsigned int timer_base, int enable)
{
sp804_control(timer_base, SP804_ENABLE, enable);
}
/*
* Enable/disable local irq register:
* @enable: enable = 1, disable = 0
*/
#define SP804_IRQEN (1 << 5)
void sp804_set_irq(unsigned int timer_base, int enable)
{
sp804_control(timer_base, SP804_IRQEN, enable);
}
/* Loads timer with value in val */
static inline void sp804_load_value(unsigned int timer_base, unsigned int val)
{
write(val, (timer_base + SP804_TIMERLOAD));
}
/* Returns current timer value */
unsigned int sp804_read_value(unsigned int timer_base)
{
return read(timer_base + SP804_TIMERVALUE);
}
/* TODO: Define macro values for duration */
void sp804_init(unsigned int timer_base, int run_mode, int wrap_mode, \
int width, int irq_enable)
{
/* 1 tick per usec */
const int duration = 250;
sp804_set_runmode(timer_base, run_mode); /* Periodic */
sp804_set_wrapmode(timer_base, wrap_mode); /* Wrapping */
sp804_set_widthmode(timer_base, width); /* 32 bit */
sp804_set_irq(timer_base, irq_enable); /* Enable */
sp804_load_value(timer_base, duration);
}

View File

@@ -1,379 +0,0 @@
#ifndef __PL011__UART__H__
#define __PL011__UART__H__
/*
* PL011 UART Generic driver implementation.
* Copyright Bahadir Balban (C) 2009
*
* 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.
*/
#if defined(VARIANT_USERSPACE)
/* FIXME: Take this value in agreement from kernel, or from kernel only */
#define PL011_BASE 0x500000
#endif
#if defined(VARIANT_BAREMETAL)
#if defined(PLATFORM_PB926)
#define PL011_BASE 0x101F1000
#elif defined(PLATFORM_EB)
#define PL011_BASE 0x10009000
#elif defined(PLATFORM_PB11MPCORE)
#define PL011_BASE 0x10009000
#endif
#endif
/* Architecture specific memory access macros */
#define read(val, address) val = *((volatile unsigned int *) address)
#define write(val, address) *((volatile unsigned int *) address) = val
/* 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)
struct pl011_uart {
unsigned long base;
unsigned int frame_errors;
unsigned int parity_errors;
unsigned int break_errors;
unsigned int overrun_errors;
unsigned int rx_timeout_errors;
};
int pl011_tx_char(unsigned int base, char c);
int pl011_rx_char(unsigned int base, char *c);
void pl011_set_baudrate(unsigned int base, unsigned int baud,
unsigned int clkrate);
void pl011_set_irq_mask(unsigned int base, unsigned int flags);
void pl011_clr_irq_mask(unsigned int base, unsigned int flags);
void pl011_irq_handler(struct pl011_uart *);
void pl011_tx_irq_handler(struct pl011_uart *uart, unsigned int);
void pl011_rx_irq_handler(struct pl011_uart *uart, unsigned int);
void pl011_error_irq_handler(struct pl011_uart *uart, unsigned int);
static inline void pl011_uart_enable(unsigned int base);
static inline void pl011_uart_disable(unsigned int base);
static inline void pl011_tx_enable(unsigned int base);
static inline void pl011_tx_disable(unsigned int base);
static inline void pl011_rx_enable(unsigned int base);
static inline void pl011_rx_disable(unsigned int base);
static inline void pl011_irq_clear(unsigned int base, unsigned int flags);
static inline unsigned int pl011_read_irqstat(unsigned int base);
static inline unsigned int pl011_read_irqmask(unsigned int base);
static inline void pl011_rx_dma_disable(unsigned int base);
static inline void pl011_rx_dma_enable(unsigned int base);
static inline void pl011_tx_dma_enable(unsigned int base);
static inline void pl011_tx_dma_disable(unsigned int base);
static inline void pl011_set_irq_fifolevel(unsigned int base,
unsigned int xfer, unsigned int level);
static inline void pl011_set_word_width(unsigned int base, int size);
static inline void pl011_disable_fifos(unsigned int base);
static inline void pl011_set_parity_even(unsigned int base);
static inline void pl011_parity_enable(unsigned int base);
static inline void pl011_set_stopbits(unsigned int base, int stopbits);
static inline void pl011_set_parity_odd(unsigned int base);
static inline void pl011_enable_fifos(unsigned int base);
static inline void pl011_parity_disable(unsigned int base);
#define PL011_UARTEN (1 << 0)
static inline void pl011_uart_enable(unsigned int base)
{
unsigned int val = 0;
read(val, (base + PL011_UARTCR));
val |= PL011_UARTEN;
write(val, (base + PL011_UARTCR));
return;
}
static inline void pl011_uart_disable(unsigned int base)
{
unsigned int val = 0;
read(val, (base + PL011_UARTCR));
val &= ~PL011_UARTEN;
write(val, (base + PL011_UARTCR));
return;
}
#define PL011_TXE (1 << 8)
static inline void pl011_tx_enable(unsigned int base)
{
unsigned int val = 0;
read(val, (base + PL011_UARTCR));
val |= PL011_TXE;
write(val, (base + PL011_UARTCR));
return;
}
static inline void pl011_tx_disable(unsigned int base)
{
unsigned int val = 0;
read(val, (base + PL011_UARTCR));
val &= ~PL011_TXE;
write(val, (base + PL011_UARTCR));
return;
}
#define PL011_RXE (1 << 9)
static inline void pl011_rx_enable(unsigned int base)
{
unsigned int val = 0;
read(val, (base + PL011_UARTCR));
val |= PL011_RXE;
write(val, (base + PL011_UARTCR));
return;
}
static inline void pl011_rx_disable(unsigned int base)
{
unsigned int val = 0;
read(val, (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 int base, int stopbits)
{
unsigned int val = 0;
read(val, (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 int base)
{
unsigned int val = 0;
read(val, (base +PL011_UARTLCR_H));
val |= PL011_PARITY_ENABLE;
write(val, (base + PL011_UARTLCR_H));
return;
}
static inline void pl011_parity_disable(unsigned int base)
{
unsigned int val = 0;
read(val, (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 int base)
{
unsigned int val = 0;
read(val, (base + PL011_UARTLCR_H));
val |= PL011_PARITY_EVEN;
write(val, (base + PL011_UARTLCR_H));
return;
}
static inline void pl011_set_parity_odd(unsigned int base)
{
unsigned int val = 0;
read(val, (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 int base)
{
unsigned int val = 0;
read(val, (base + PL011_UARTLCR_H));
val |= PL011_ENABLE_FIFOS;
write(val, (base + PL011_UARTLCR_H));
return;
}
static inline void pl011_disable_fifos(unsigned int base)
{
unsigned int val = 0;
read(val, (base + PL011_UARTLCR_H));
val &= ~PL011_ENABLE_FIFOS;
write(val, (base + PL011_UARTLCR_H));
return;
}
#define PL011_WORD_WIDTH_SHIFT (5)
/* Sets the transfer word width for the data register. */
static inline void pl011_set_word_width(unsigned int base, int size)
{
unsigned int val = 0;
if(size < 5 || size > 8) /* Default is 8 */
size = 8;
/* Clear size field */
read(val, (base + PL011_UARTLCR_H));
val &= ~(0x3 << PL011_WORD_WIDTH_SHIFT);
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
*/
read(val, (base + PL011_UARTLCR_H));
val |= (size - 5) << PL011_WORD_WIDTH_SHIFT;
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 int 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;
}
/* returns which irqs are masked */
static inline unsigned int pl011_read_irqmask(unsigned int base)
{
unsigned int flags;
read(flags, (base + PL011_UARTIMSC));
return flags;
}
/* returns masked irq status */
static inline unsigned int pl011_read_irqstat(unsigned int base)
{
unsigned int irqstatus;
read(irqstatus, (base + PL011_UARTMIS));
return irqstatus;
}
/* Clears the given asserted irqs */
static inline void pl011_irq_clear(unsigned int base, unsigned int flags)
{
if(flags > 0x3FF) {
/* Invalid irq clearing bitvector */
return;
}
/* Simply write the flags since it's a write-only register */
write(flags, (base + PL011_UARTICR));
return;
}
#define PL011_TXDMAEN (1 << 1)
#define PL011_RXDMAEN (1 << 0)
/*
* Enables dma transfers for uart. The dma controller
* must be initialised, set-up and enabled separately.
*/
static inline void pl011_tx_dma_enable(unsigned int base)
{
unsigned int val = 0;
read(val, (base + PL011_UARTDMACR));
val |= PL011_TXDMAEN;
write(val, (base + PL011_UARTDMACR));
return;
}
/* Disables dma transfers for uart */
static inline void pl011_tx_dma_disable(unsigned int base)
{
unsigned int val = 0;
read(val, (base + PL011_UARTDMACR));
val &= ~PL011_TXDMAEN;
write(val, (base + PL011_UARTDMACR));
return;
}
static inline void pl011_rx_dma_enable(unsigned int base)
{
unsigned int val = 0;
read(val, (base + PL011_UARTDMACR));
val |= PL011_RXDMAEN;
write(val, (base + PL011_UARTDMACR));
return;
}
static inline void pl011_rx_dma_disable(unsigned int base)
{
unsigned int val = 0;
read(val, (base + PL011_UARTDMACR));
val &= ~PL011_RXDMAEN;
write(val, (base +PL011_UARTDMACR));
return;
}
int pl011_initialise(struct pl011_uart *uart);
#endif /* __PL011__UART__ */

View File

@@ -1,123 +0,0 @@
/*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <pl011_uart.h>
/* UART-specific internal error codes */
#define PL011_ERROR 1
#define PL011_EAGAIN 2
/* 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)
int pl011_tx_char(unsigned int base, char c)
{
unsigned int val = 0;
read(val, (base + PL011_UARTFR));
if(val & PL011_TXFF) { /* TX FIFO Full */
return -PL011_EAGAIN;
}
write(c, (base + PL011_UARTDR));
return 0;
}
int pl011_rx_char(unsigned int base, char * c)
{
unsigned int data;
unsigned int val = 0;
read(val, (base + PL011_UARTFR));
if(val & PL011_RXFE) { /* RX FIFO Empty */
return -PL011_EAGAIN;
}
read(data, (base + PL011_UARTDR));
*c = (char) data;
if((data >> 8) & 0xF) { /* There were errors */
return -1; /* Signal error in xfer */
}
return 0; /* No error return */
}
/*
* 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 int 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
*/
read(val, (base + PL011_UARTLCR_H));
write(val, (base + PL011_UARTLCR_H));
return;
}
/* Masks the irqs given in the flags bitvector. */
void pl011_set_irq_mask(unsigned int base, unsigned int flags)
{
unsigned int val = 0;
if(flags > 0x3FF) { /* Invalid irqmask bitvector */
return;
}
read(val, (base + PL011_UARTIMSC));
val |= flags;
write(val, (base + PL011_UARTIMSC));
return;
}
/* Clears the irqs given in flags from masking */
void pl011_clr_irq_mask(unsigned int base, unsigned int flags)
{
unsigned int val = 0;
if(flags > 0x3FF) {
/* Invalid irqmask bitvector */
return;
}
read(val, (base + PL011_UARTIMSC));
val &= ~flags;
write(val, (base + PL011_UARTIMSC));
return;
}

View File

@@ -1,60 +0,0 @@
/*
* User space uart driver.
*
* Copyright (C) 2009, B Labs Ltd.
*/
#include <pl011_uart.h>
/*
* Every task who wants to use this uart needs
* to initialize an instance of this
*/
struct pl011_uart uart;
/*
* Initialises the uart class data structures, and the device.
* Terminal-like operation is assumed for default settings.
*/
int pl011_initialise(struct pl011_uart *uart)
{
uart->frame_errors = 0;
uart->parity_errors = 0;
uart->break_errors = 0;
uart->overrun_errors = 0;
/* 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);
/* Disable all irqs */
pl011_set_irq_mask(uart->base, 0x3FF);
/* Enable rx, tx, and uart chip */
pl011_tx_enable(uart->base);
pl011_rx_enable(uart->base);
pl011_uart_enable(uart->base);
return 0;
}
void platform_init(void)
{
uart.base = PL011_BASE;
pl011_initialise(&uart);
}

View File

@@ -1,27 +0,0 @@
/*
* Address allocation pool.
*
* Copyright (C) 2007 Bahadir Balban
*/
#ifndef __ADDR_H__
#define __ADDR_H__
#include <l4lib/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_with_idpool(struct address_pool *pool,
struct id_pool *idpool,
unsigned long start, unsigned long end);
int address_pool_init(struct address_pool *pool,
unsigned long start, unsigned long end,
unsigned int size);
void *address_new(struct address_pool *pool, int nitems, int size);
int address_del(struct address_pool *, void *addr, int nitems, int size);
#endif /* __ADDR_H__ */

View File

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

View File

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

View File

@@ -1,92 +0,0 @@
/*
* System call prototypes.
*
* Copyright (C) 2007 Bahadir Balban
*/
#ifndef __ARM_SYSCALLS_H__
#define __ARM_SYSCALLS_H__
#include <l4lib/arch/types.h>
#include <l4lib/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);
/* To be supplied by server tasks. */
void *virt_to_phys(void *);
void *phys_to_virt(void *);
#endif /* __ARM_SYSCALLS_H__ */

View File

@@ -1,366 +0,0 @@
/*
* 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 <l4lib/arch/syscalls.h>
#include <l4/macros.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_RW_FLAGS, ids.tid)) < 0)
return PTR_ERR(err);
return virt;
}
/* A helper that translates and maps a physical address to virtual */
static inline void *l4_unmap_helper(void *virt, int npages)
{
struct task_ids ids;
l4_getid(&ids);
l4_unmap(virt, npages, ids.tid);
l4_del_virtual(virt, npages);
return 0;
}
#define L4_EXIT_MASK 0xFFFF
static inline void l4_exit(unsigned int exit_code)
{
struct task_ids ids;
l4_getid(&ids);
l4_thread_control(THREAD_DESTROY |
(exit_code & L4_EXIT_MASK),
&ids);
}
#endif /* __L4LIB_SYSLIB_H__ */

View File

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

View File

@@ -1,93 +0,0 @@
/*
* 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>
/*
* See kernel glue/arch/message.h for utcb details
*/
extern struct kip *kip;
/*
* 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;
}
/* Functions to read/write utcb registers */
static inline unsigned int read_mr(int offset)
{
if (offset < MR_TOTAL)
return l4_get_utcb()->mr[offset];
else
return l4_get_utcb()->mr_rest[offset - MR_TOTAL];
}
static inline void write_mr(unsigned int offset, unsigned int val)
{
if (offset < MR_TOTAL)
l4_get_utcb()->mr[offset] = val;
else
l4_get_utcb()->mr_rest[offset - MR_TOTAL] = val;
}
static inline void *utcb_full_buffer()
{
return &l4_get_utcb()->mr_rest[0];
}
static inline char *utcb_full_strcpy_from(const char *src)
{
return strncpy((char *)&l4_get_utcb()->mr_rest[0], src,
L4_UTCB_FULL_BUFFER_SIZE);
}
static inline void *utcb_full_memcpy_from(const char *src, int size)
{
return memcpy(&l4_get_utcb()->mr_rest[0], src,
min(size, L4_UTCB_FULL_BUFFER_SIZE));
}
static inline char *utcb_full_strcpy_to(char *dst)
{
return strncpy(dst, (char *)&l4_get_utcb()->mr_rest[0],
L4_UTCB_FULL_BUFFER_SIZE);
}
static inline void *utcb_full_memcpy_to(char *dst, int size)
{
return memcpy(dst, &l4_get_utcb()->mr_rest[0],
min(size, L4_UTCB_FULL_BUFFER_SIZE));
}
#endif /* !__ASSEMBLY__ */
#endif /* __ARM_UTCB_H__ */

View File

@@ -1,44 +0,0 @@
#ifndef __BIT_H__
#define __BIT_H__
#include <l4lib/types.h>
unsigned int __clz(unsigned int bitvector);
int find_and_set_first_free_bit(u32 *word, unsigned int lastbit);
int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit,
int nbits);
int check_and_clear_bit(u32 *word, int bit);
int check_and_clear_contig_bits(u32 *word, int first, int nbits);
int check_and_set_bit(u32 *word, int bit);
/* Set */
static inline void setbit(unsigned int *w, unsigned int flags)
{
*w |= flags;
}
/* Clear */
static inline void clrbit(unsigned int *w, unsigned int flags)
{
*w &= ~flags;
}
/* Test */
static inline int tstbit(unsigned int *w, unsigned int flags)
{
return *w & flags;
}
/* Test and clear */
static inline int tstclr(unsigned int *w, unsigned int flags)
{
int res = tstbit(w, flags);
clrbit(w, flags);
return res;
}
#endif /* __BIT_H__ */

View File

@@ -1,60 +0,0 @@
/*
* 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>
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);
}
#endif /* __LIBL4_CAPABILITY_H__ */

View File

@@ -1,12 +0,0 @@
#ifndef __CAP_PRINT_H__
#define __CAP_PRINT_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);
#endif /* __CAP_PRINT_H__*/

View File

@@ -1,31 +0,0 @@
#ifndef __IDPOOL_H__
#define __IDPOOL_H__
#include <l4lib/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));
}
struct id_pool *id_pool_new_init(int mapsize);
int id_new(struct id_pool *pool);
int id_del(struct id_pool *pool, int id);
int id_get(struct id_pool *pool, int id);
int id_is_empty(struct id_pool *pool);
int ids_new_contiguous(struct id_pool *pool, int numids);
int ids_del_contiguous(struct id_pool *pool, int first, int numids);
#endif /* __IDPOOL_H__ */

View File

@@ -1,19 +0,0 @@
/*
* Stack space helper routines.
*
* Copyright (C) 2009 B Labs Ltd.
*/
#ifndef __LIB_STACK_H__
#define __LIB_STACK_H__
/* Checks if l4_set_stack_params is called. */
#define IS_STACK_SETUP() (lib_stack_size)
int stack_pool_init(unsigned long stack_start,
unsigned long stack_end,
unsigned long stack_size);
void *get_stack_space(void);
int delete_stack_space(void *stack_address);
#endif /* __LIB_STACK_H__ */

View File

@@ -1,43 +0,0 @@
/*
* Thread control block.
*
* Copyright (C) 2009 B Labs Ltd.
*/
#ifndef __LIB_TCB_H__
#define __LIB_TCB_H__
#include <l4/lib/list.h>
/* Keeps all the struct utcb_descs belonging to a thread group together. */
struct l4lib_utcb_head {
struct link list;
};
/* A simple thread control block for the thread library. */
struct l4lib_tcb {
/* Task list */
struct link list;
/* Task id */
int tid;
/* Chain of utcb descriptors */
struct l4lib_utcb_head *utcb_head;
/* Stack and utcb address */
unsigned long utcb_addr;
unsigned long stack_addr;
};
/* All the threads handled by the thread lib are kept in this list. */
struct l4lib_global_list {
int total;
struct link list;
};
struct l4lib_tcb *l4lib_find_task(int tid);
struct l4lib_tcb *l4_tcb_alloc_init(struct l4lib_tcb *parent, unsigned int flags);
void l4lib_global_add_task(struct l4lib_tcb *task);
void l4lib_global_remove_task(struct l4lib_tcb *task);
#endif /* __LIB_TCB_H__ */

View File

@@ -1,36 +0,0 @@
#ifndef __L4_THREAD_H__
#define __L4_THREAD_H__
#include <l4lib/arch/utcb.h>
#include <l4lib/arch/types.h>
struct l4_thread_struct {
l4id_t tlid; /* Thread local id */
struct task_ids ids; /* Thread L4-defined ids */
struct utcb *utcb; /* Thread utcb */
unsigned long stack_start; /* Thread start of stack */
};
/* -- Bora start -- */
/*
* A helper macro easing utcb space creation,
* FIXME: We need to fix address allocation path, so as to use
* actual size of units instead of page size
*/
#define DECLARE_UTCB_SPACE(name, entries) \
char name[entries * PAGE_SIZE] ALIGN(PAGE_SIZE);
int l4_set_stack_params(unsigned long stack_top,
unsigned long stack_bottom,
unsigned long stack_size);
int l4_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end);
int l4_thread_create(struct task_ids *ids, unsigned int flags,
int (*func)(void *), void *arg);
void l4_thread_exit(int retval);
/* -- Bora start -- */
#endif /* __L4_THREAD_H__ */

View File

@@ -1,33 +0,0 @@
/*
* UTCB handling common helper routines.
*
* Copyright (C) 2009 B Labs Ltd.
*/
#ifndef __UTCB_COMMON_H__
#define __UTCB_COMMON_H__
#include <l4/lib/list.h>
#include <l4lib/thread/tcb.h>
struct l4lib_utcb_desc {
struct link list;
unsigned long utcb_base;
struct id_pool *slots;
};
int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end);
unsigned long utcb_new_slot(struct l4lib_utcb_desc *desc);
int utcb_delete_slot(struct l4lib_utcb_desc *desc, unsigned long address);
struct l4lib_utcb_desc *utcb_new_desc(void);
int utcb_delete_desc(struct l4lib_utcb_desc *desc);
/* Checks if l4_set_stack_params is called. */
#define IS_UTCB_SETUP() (lib_utcb_range_size)
unsigned long get_utcb_addr(struct l4lib_tcb *task);
int delete_utcb_addr(struct l4lib_tcb *task);
#endif /* __UTCB_COMMON_H__ */

View File

@@ -1,57 +0,0 @@
/*
* This module allocates an unused address range from
* a given memory region defined as the pool range.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4lib/addr.h>
#include <stdio.h>
/*
* Initializes an address pool, but uses an already
* allocated id pool for it.
*/
int address_pool_init_with_idpool(struct address_pool *pool,
struct id_pool *idpool,
unsigned long start, unsigned long end)
{
pool->idpool = idpool;
pool->start = start;
pool->end = end;
return 0;
}
int address_pool_init(struct address_pool *pool,
unsigned long start, unsigned long end,
unsigned int size)
{
if ((pool->idpool = id_pool_new_init(__pfn(end - start) )) < 0)
return (int)pool->idpool;
pool->start = start;
pool->end = end;
return 0;
}
void *address_new(struct address_pool *pool, int nitems, int size)
{
unsigned int idx;
if ((int)(idx = ids_new_contiguous(pool->idpool, nitems)) < 0)
return 0;
return (void *)(idx * size) + pool->start;
}
int address_del(struct address_pool *pool, void *addr, int nitems, int size)
{
unsigned long idx = (addr - (void *)pool->start) / size;
if (ids_del_contiguous(pool->idpool, idx, nitems) < 0) {
printf("%s: Invalid address range returned to "
"virtual address pool.\n", __FUNCTION__);
return -1;
}
return 0;
}

View File

@@ -1,84 +0,0 @@
/*
* Generic to arch-specific interface for
* exchange_registers()
*
* Copyright (C) 2008 Bahadir Balban
*/
#include <l4/macros.h>
#include <l4lib/exregs.h>
#include <l4lib/arch/syslib.h>
#include INC_GLUE(message.h)
void exregs_print_registers(void)
{
struct exregs_data exregs;
/* Read registers */
memset(&exregs, 0, sizeof(exregs));
exregs.valid_vect = ~0; /* Set all flags */
exregs.flags |= EXREGS_READ;
exregs.flags |= EXREGS_SET_UTCB;
exregs.flags |= EXREGS_SET_PAGER;
BUG_ON(l4_exchange_registers(&exregs, self_tid()) < 0);
/* Print out registers */
printf("Task (%x) register state upon fault:\n", self_tid());
printf("R0: 0x%x\n", exregs.context.r0);
printf("R1: 0x%x\n", exregs.context.r1);
printf("R2: 0x%x\n", exregs.context.r2);
printf("R3: 0x%x\n", exregs.context.r3);
printf("R4: 0x%x\n", exregs.context.r4);
printf("R5: 0x%x\n", exregs.context.r5);
printf("R6: 0x%x\n", exregs.context.r6);
printf("R7: 0x%x\n", exregs.context.r7);
printf("R8: 0x%x\n", exregs.context.r8);
printf("R9: 0x%x\n", exregs.context.r9);
printf("R10: 0x%x\n", exregs.context.r10);
printf("R11: 0x%x\n", exregs.context.r11);
printf("R12: 0x%x\n", exregs.context.r12);
printf("R13: 0x%x\n", exregs.context.sp);
printf("R14: 0x%x\n", exregs.context.lr);
printf("R15: 0x%x\n", exregs.context.pc);
printf("Pager: 0x%x\n", exregs.pagerid);
printf("Utcb @ 0x%lx\n", exregs.utcb_address);
}
void exregs_set_mr(struct exregs_data *s, int offset, unsigned long val)
{
/* Get MR0 */
u32 *mr = &s->context.MR0_REGISTER;
/* Sanity check */
BUG_ON(offset > MR_TOTAL || offset < 0);
/* Set MR */
mr[offset] = val;
/* Set valid bit for mr register */
s->valid_vect |= FIELD_TO_BIT(exregs_context_t, MR0_REGISTER) << offset;
}
void exregs_set_pager(struct exregs_data *s, l4id_t pagerid)
{
s->pagerid = pagerid;
s->flags |= EXREGS_SET_PAGER;
}
void exregs_set_utcb(struct exregs_data *s, unsigned long virt)
{
s->utcb_address = virt;
s->flags |= EXREGS_SET_UTCB;
}
void exregs_set_stack(struct exregs_data *s, unsigned long sp)
{
s->context.sp = sp;
s->valid_vect |= FIELD_TO_BIT(exregs_context_t, sp);
}
void exregs_set_pc(struct exregs_data *s, unsigned long pc)
{
s->context.pc = pc;
s->valid_vect |= FIELD_TO_BIT(exregs_context_t, pc);
}

View File

@@ -1,75 +0,0 @@
/*
* Copyright (C) 2009 Bahadir Balban
*/
#include <l4lib/arch/asm.h>
#include <l4lib/mutex.h>
/*
* NOTES:
*
* Recap on swp:
*
* swp rx, ry, [rz]
*
* In one instruction:
*
* 1) Stores the value in ry into location pointed by rz.
* 2) Loads the value in the location of rz into rx.
* By doing so, in one instruction one can attempt to lock
* a word, and discover whether it was already locked.
*
* Why use tid of thread to lock mutex instead of
* a single lock value?
*
* Because in one atomic instruction, not only the locking attempt
* should be able to indicate whether it is locked, but also
* the contentions. A unified lock value would not be sufficient.
* The only way to indicate a contended lock is to store the
* unique TID of the locker.
*/
/*
* Any non-negative value that is a potential TID
* (including 0) means mutex is locked.
*/
/*
* @r0 = address of mutex word
* @r1 = unique tid of current thread
*/
BEGIN_PROC(__l4_mutex_lock)
swp r2, r1, [r0]
cmp r2, #L4_MUTEX_UNLOCKED @ Was the lock available?
movne r0, #L4_MUTEX_CONTENDED @ Indicate failure
moveq r0, #L4_MUTEX_SUCCESS @ Indicate success
mov pc, lr
END_PROC(__l4_mutex_lock)
/*
* @r0 = address of mutex word
* @r1 = unique tid of current thread
*/
BEGIN_PROC(__l4_mutex_unlock)
mov r3, #L4_MUTEX_UNLOCKED
swp r2, r3, [r0]
cmp r2, r1 @ Check lock had original tid value
movne r0, #L4_MUTEX_CONTENDED @ Indicate contention
moveq r0, #L4_MUTEX_SUCCESS @ Indicate no contention
cmp r2, #L4_MUTEX_UNLOCKED @ Or - was it already unlocked?
1:
beq 1b @ If so busy-spin to indicate bug.
mov pc, lr
END_PROC(__l4_mutex_unlock)
/*
* r0 = byte address to read from.
*/
BEGIN_PROC(l4_atomic_dest_readb)
mov r1, r0 @ Move byte address to r1
mov r2, #0 @ Move 0 to r2
swpb r0, r2, [r1] @ Write 0 to byte location, while reading its value to r0
mov pc, lr @ Return byte location value
END_PROC(l4_atomic_dest_readb)

View File

@@ -1,12 +0,0 @@
#include <l4lib/arch/asm.h>
BEGIN_PROC(setup_new_thread)
ldr r0, [sp], #-4 @ Load first argument
mov lr, pc @ Save return address
ldr pc, [sp], #-4 @ Load function pointer from stack
b l4_thread_exit @ Call l4_thread_exit for cleanup
new_thread_exit:
b new_thread_exit @ Never reaches here
END_PROC(setup_new_thread)

View File

@@ -1,220 +0,0 @@
/*
* Userspace system call interface.
*
* Copyright (C) 2007 - 2009 Bahadir Balban
*/
#include <l4lib/arch/asm.h>
#include <l4lib/arch/utcb.h>
#include <l4/generic/space.h>
#include <l4/macros.h>
#include INC_GLUE(message.h)
/* Old macro */
#if 0
.macro utcb_address rx
ldr \rx, =utcb
.endm
#endif
/* New macro does double dereference */
.macro utcb_address rx
ldr \rx, =kip_utcb_ref @ First get pointer to utcb pointer in KIP
ldr \rx, [\rx] @ Get pointer to UTCB address from UTCB pointer in KIP
ldr \rx, [\rx] @ Get the utcb address
.endm
BEGIN_PROC(l4_thread_switch)
ldr r12, =__l4_thread_switch
ldr pc, [r12] @ Jump into the SWI. Kernel returns to LR_USR, which is the caller.
END_PROC(l4_thread_switch)
/*
* The syscall returns process ids. This function saves the returned values in the
* arguments passed by reference. @r0 = struct task_ids *
*/
BEGIN_PROC(l4_getid)
ldr r12, =__l4_getid @ See l4_kdata_read for why its so simple.
ldr pc, [r12] @ Return.
END_PROC(l4_getid)
/*
* For clone() we need special assembler handling
* Same signature as ipc(): @r0 = to, @r1 = from @r2 = flags
*
* NOTE: Note that this breaks l4 system call interface,
* this should be moved elsewhere and modified using existing l4 mechanisms.
*/
BEGIN_PROC(arch_clone)
stmfd sp!, {r4-r8,lr} @ Save context.
utcb_address r12 @ Get utcb address.
ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5
ldr r12, =__l4_ipc
mov lr, pc
ldr pc, [r12] @ Perform the ipc()
/*
* At this moment:
* - MR_RETURN tells us whether we are parent or child (or have failed).
* - Child has new SP set, with |func_ptr|arg1|{End of stack}SP<-| on stack.
* - Child needs exit logic when its function is finished.
*/
cmp r0, #0 @ Check ipc success
blt ipc_failed
cmp MR_RETURN_REGISTER, #0 @ Check ipc return register MR_RETURN.
blt clone_failed @ Ipc was ok but clone() failed.
bgt parent_return @ It has child pid, goto parent return.
child:
ldr r0, [sp, #-4]! @ Load child's first argument.
mov lr, pc @ Save return address
ldr pc, [sp, #-4]! @ Load function pointer from stack
child_exit:
b child_exit @ We infinitely loop for now.
@ Return with normal ipc return sequence
parent_return:
clone_failed:
ipc_failed:
utcb_address r12 @ Get utcb
stmia r12, {r3-r8} @ Store mrs.
ldmfd sp!, {r4-r8,pc} @ Return restoring pc and context.
END_PROC(arch_clone)
/*
* Inter-process communication. Loads message registers as arguments before the call,
* and stores them as results after the call. @r0 = to, @r1 = from.
*/
BEGIN_PROC(l4_ipc)
stmfd sp!, {r4-r8,lr} @ Save context.
utcb_address r12 @ Get utcb address.
ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5
ldr r12, =__l4_ipc
mov lr, pc
ldr pc, [r12]
utcb_address r12 @ Get utcb address.
stmia r12, {r3-r8} @ Store 6 Message registers to utcb. MR0-MR5
ldmfd sp!, {r4-r8,pc} @ Return restoring pc, and context.
END_PROC(l4_ipc)
/*
* System call that maps an area of memory into the given address space.
* @r0 = physical address, @r1 = virtual address, @r2 = map size in pages,
* @r3 = map flags, @r4 = The tgid of the address space to map.
*/
BEGIN_PROC(l4_map)
stmfd sp!, {r4, lr}
ldr r4, [sp, #8] @ FIXME: Is this right?
ldr r12, =__l4_map
mov lr, pc @ We must return here to restore r4.
ldr pc, [r12]
ldmfd sp!, {r4, pc}
END_PROC(l4_map)
/*
* Reads/manipulates capabilities of a thread, particularly a pager.
* @r0 = request type, @r1 = request flags, @r2 = Capability buffer pointer
*/
BEGIN_PROC(l4_capability_control)
stmfd sp!, {lr}
ldr r12, =__l4_capability_control
mov lr, pc
ldr pc, [r12]
ldmfd sp!, {pc} @ Restore original lr and return.
END_PROC(l4_capability_control)
/*
* System call that unmaps an area of memory into the given address space.
* @r0 = virtual, @r1 = pages, @r2 = tid of address space to unmap
*/
BEGIN_PROC(l4_unmap)
stmfd sp!, {lr}
ldr r12, =__l4_unmap
mov lr, pc
ldr pc, [r12]
ldmfd sp!, {pc} @ Restore original lr and return.
END_PROC(l4_unmap)
/*
* System call that controls containers and their parameters.
* @r0 = request type, @r1 = request flags, @r2 = io buffer ptr
*/
BEGIN_PROC(l4_container_control)
stmfd sp!, {lr}
ldr r12, =__l4_container_control
mov lr, pc
ldr pc, [r12]
ldmfd sp!, {pc} @ Restore original lr and return.
END_PROC(l4_container_control)
/*
* System call that gets or sets the time info structure.
* @r0 = ptr to time structure @r1 = set or get. set = 1, get = 0.
*/
BEGIN_PROC(l4_time)
stmfd sp!, {lr}
ldr r12, =__l4_time
mov lr, pc
ldr pc, [r12]
ldmfd sp!, {pc} @ Restore original lr and return.
END_PROC(l4_time)
/*
* System call that controls thread creation, destruction and modification.
* @r0 = thread action, @r1 = &ids, @r2 = utcb address
*/
BEGIN_PROC(l4_thread_control)
stmfd sp!, {lr}
ldr r12, =__l4_thread_control
mov lr, pc
ldr pc, [r12]
ldmfd sp!, {pc} @ Restore original lr and return.
END_PROC(l4_thread_control)
/*
* System call that modifies ipc blocked sender lists of receivers.
* @r0 = Action (e.g. block/unblock), @r1 = sender id, @r2 = sender tag
*/
BEGIN_PROC(l4_ipc_control)
stmfd sp!, {lr}
ldr r12, =__l4_ipc_control
mov lr, pc
ldr pc, [r12]
ldmfd sp!, {pc} @ Restore original lr and return.
END_PROC(l4_ipc_control)
/*
* Manipulates address spaces, e.g. sets up shared memory areas between threads
* @r0 = operation code, @r1 = operation flags, @r2 = An id (irqnum, or capid)
*/
BEGIN_PROC(l4_irq_control)
stmfd sp!, {lr}
ldr r12, =__l4_irq_control
mov lr, pc
ldr pc, [r12]
ldmfd sp!, {pc} @ Restore original lr and return.
END_PROC(l4_irq_control)
/*
* Locks/unlocks a userspace mutex.
* @r0 = mutex virtual address, @r1 = mutex operation code
*/
BEGIN_PROC(l4_mutex_control)
stmfd sp!, {lr}
ldr r12, =__l4_mutex_control
mov lr, pc
ldr pc, [r12]
ldmfd sp!, {pc} @ Restore original lr and return.
END_PROC(l4_mutex_control)
/*
* Sets registers of a thread and its pager.
* @r0 = ptr to exregs_data structure, @r1 = tid of thread.
*/
BEGIN_PROC(l4_exchange_registers)
stmfd sp!, {lr}
ldr r12, =__l4_exchange_registers
mov lr, pc
ldr pc, [r12]
ldmfd sp!, {pc} @ Restore original lr and return.
END_PROC(l4_exchange_registers)

View File

@@ -1,109 +0,0 @@
/*
* Bit manipulation functions.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4lib/bit.h>
#include <stdio.h>
#include <l4/macros.h>
#include INC_GLUE(memory.h)
/* Emulation of ARM's CLZ (count leading zeroes) instruction */
unsigned int __clz(unsigned int bitvector)
{
unsigned int x = 0;
while((!(bitvector & ((unsigned)1 << 31))) && (x < 32)) {
bitvector <<= 1;
x++;
}
return x;
}
int find_and_set_first_free_bit(u32 *word, unsigned int limit)
{
int success = 0;
int i;
for(i = 0; i < limit; i++) {
/* Find first unset bit */
if (!(word[BITWISE_GETWORD(i)] & BITWISE_GETBIT(i))) {
/* Set it */
word[BITWISE_GETWORD(i)] |= BITWISE_GETBIT(i);
success = 1;
break;
}
}
/* Return bit just set */
if (success)
return i;
else
return -1;
}
int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit,
int nbits)
{
int i = 0, first = 0, last = 0, found = 0;
/* Can't allocate more than the limit */
if (nbits > limit)
return -1;
/* This is a state machine that checks n contiguous free bits. */
while (i + nbits <= limit) {
first = i;
last = i;
while (!(word[BITWISE_GETWORD(last)] & BITWISE_GETBIT(last))) {
last++;
i++;
if (last == first + nbits) {
found = 1;
break;
}
}
if (found)
break;
i++;
}
/* If found, set the bits */
if (found) {
for (int x = first; x < first + nbits; x++)
word[BITWISE_GETWORD(x)] |= BITWISE_GETBIT(x);
return first;
} else
return -1;
}
int check_and_clear_bit(u32 *word, int bit)
{
/* Check that bit was set */
if (word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit)) {
word[BITWISE_GETWORD(bit)] &= ~BITWISE_GETBIT(bit);
return 0;
} else {
printf("Trying to clear already clear bit\n");
return -1;
}
}
int check_and_set_bit(u32 *word, int bit)
{
/* Check that bit was clear */
if (!(word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit))) {
word[BITWISE_GETWORD(bit)] |= BITWISE_GETBIT(bit);
return 0;
} else {
//printf("Trying to set already set bit\n");
return -1;
}
}
int check_and_clear_contig_bits(u32 *word, int first, int nbits)
{
for (int i = first; i < first + nbits; i++)
if (check_and_clear_bit(word, i) < 0)
return -1;
return 0;
}

View File

@@ -1,117 +0,0 @@
/* Capability printing generic routines */
#include <l4lib/capability/cap_print.h>
#include <stdio.h>
void cap_dev_print(struct capability *cap)
{
switch (cap_devtype(cap)) {
case CAP_DEVTYPE_UART:
printf("Device type:\t\t\t%s%d\n", "UART", cap_devnum(cap));
break;
case CAP_DEVTYPE_TIMER:
printf("Device type:\t\t\t%s%d\n", "Timer", cap_devnum(cap));
break;
case CAP_DEVTYPE_CLCD:
printf("Device type:\t\t\t%s%d\n", "CLCD", cap_devnum(cap));
break;
default:
return;
}
printf("Device Irq:\t\t%d\n", cap->irq);
}
void cap_print(struct capability *cap)
{
printf("Capability id:\t\t\t%d\n", cap->capid);
printf("Capability resource id:\t\t%d\n", cap->resid);
printf("Capability owner id:\t\t%d\n",cap->owner);
switch (cap_type(cap)) {
case CAP_TYPE_TCTRL:
printf("Capability type:\t\t%s\n", "Thread Control");
break;
case CAP_TYPE_EXREGS:
printf("Capability type:\t\t%s\n", "Exchange Registers");
break;
case CAP_TYPE_MAP_PHYSMEM:
if (!cap_is_devmem(cap)) {
printf("Capability type:\t\t%s\n", "Map/Physmem");
} else {
printf("Capability type:\t\t%s\n", "Map/Physmem/Device");
cap_dev_print(cap);
}
break;
case CAP_TYPE_MAP_VIRTMEM:
printf("Capability type:\t\t%s\n", "Map/Virtmem");
break;
case CAP_TYPE_IPC:
printf("Capability type:\t\t%s\n", "Ipc");
break;
case CAP_TYPE_UMUTEX:
printf("Capability type:\t\t%s\n", "Mutex");
break;
case CAP_TYPE_IRQCTRL:
printf("Capability type:\t\t%s\n", "IRQ Control");
break;
case CAP_TYPE_QUANTITY:
printf("Capability type:\t\t%s\n", "Quantitative");
break;
case CAP_TYPE_CAP:
printf("Capability type:\t\t%s\n", "Capability Control");
break;
default:
printf("Capability type:\t\t%s, cap_type=0x%x\n",
"Unknown", cap_type(cap));
break;
}
switch (cap_rtype(cap)) {
case CAP_RTYPE_THREAD:
printf("Capability resource type:\t%s\n", "Thread");
break;
case CAP_RTYPE_SPACE:
printf("Capability resource type:\t%s\n", "Space");
break;
case CAP_RTYPE_CONTAINER:
printf("Capability resource type:\t%s\n", "Container");
break;
case CAP_RTYPE_THREADPOOL:
printf("Capability resource type:\t%s\n", "Thread Pool");
break;
case CAP_RTYPE_SPACEPOOL:
printf("Capability resource type:\t%s\n", "Space Pool");
break;
case CAP_RTYPE_MUTEXPOOL:
printf("Capability resource type:\t%s\n", "Mutex Pool");
break;
case CAP_RTYPE_MAPPOOL:
printf("Capability resource type:\t%s\n", "Map Pool (PMDS)");
break;
case CAP_RTYPE_CPUPOOL:
printf("Capability resource type:\t%s\n", "Cpu Pool");
break;
case CAP_RTYPE_CAPPOOL:
printf("Capability resource type:\t%s\n", "Capability Pool");
break;
default:
printf("Capability resource type:\t%s, id=0x%x\n", "Unknown",
cap_rtype(cap));
break;
}
printf("\n");
}
void cap_array_print(int total_caps, struct capability *caparray)
{
printf("Capabilities\n"
"~~~~~~~~~~~~\n");
for (int i = 0; i < total_caps; i++)
cap_print(&caparray[i]);
printf("\n");
}

View File

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

View File

@@ -1,97 +0,0 @@
/*
* Stack management in libl4thread.
*
* Copyright © 2009 B Labs Ltd.
*/
#include <stdio.h>
#include <l4/api/errno.h>
#include <l4lib/addr.h>
#include <l4lib/mutex.h>
#include <l4lib/thread/stack.h>
/* Extern declarations */
extern struct l4_mutex lib_mutex;
/* Global variables */
unsigned long lib_stack_size;
/* Stack virtual region pool */
static struct address_pool stack_region_pool;
int stack_pool_init(unsigned long stack_start,
unsigned long stack_end,
unsigned long stack_size)
{
int err;
/* Initialise the global stack virtual address pool. */
if ((err = address_pool_init(&stack_region_pool,
stack_start, stack_end,
stack_size) < 0)) {
printf("Stack address pool initialisation failed.\n");
return err;
}
return 0;
}
void *get_stack_space(void)
{
return address_new(&stack_region_pool, 1, lib_stack_size);
}
int delete_stack_space(void *stack_address)
{
return address_del(&stack_region_pool, stack_address, 1, lib_stack_size);
}
int l4_set_stack_params(unsigned long stack_top,
unsigned long stack_bottom,
unsigned long stack_size)
{
/* Ensure that arguments are valid. */
if (IS_STACK_SETUP()) {
printf("libl4thread: You have already called: %s.\n",
__FUNCTION__);
return -EPERM;
}
if (!stack_top || !stack_bottom) {
printf("libl4thread: Stack address range cannot contain "
"0x0 as a start and/or end address(es).\n");
return -EINVAL;
}
// FIXME: Aligning should be taken into account.
/*
* Stack grows downward so the top of the stack will have
* the lowest numbered address.
*/
if (stack_top >= stack_bottom) {
printf("libl4thread: Stack bottom address must be bigger "
"than stack top address.\n");
return -EINVAL;
}
if (!stack_size) {
printf("libl4thread: Stack size cannot be zero.\n");
return -EINVAL;
}
/* stack_size at least must be equal to the difference. */
if ((stack_bottom - stack_top) < stack_size) {
printf("libl4thread: The given range size is lesser than "
"the stack size(0x%x).\n", stack_size);
return -EINVAL;
}
/* Arguments passed the validity tests. */
/* Initialize internal variables. */
lib_stack_size = stack_size;
/* Initialize stack virtual address pool. */
if (stack_pool_init(stack_top, stack_bottom, stack_size) < 0)
BUG();
/* Initialize the global mutex. */
l4_mutex_init(&lib_mutex);
return 0;
}

View File

@@ -1,65 +0,0 @@
/*
* Thread management in libl4thread.
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <stdio.h>
#include <malloc/malloc.h>
#include <l4/api/errno.h>
#include <l4/api/thread.h>
#include <l4lib/thread/tcb.h>
#include <l4/macros.h>
/* Global task list. */
struct l4lib_global_list global_tasks = {
.list = { &global_tasks.list, &global_tasks.list },
.total = 0,
};
/* Function definitions */
void l4lib_global_add_task(struct l4lib_tcb *task)
{
BUG_ON(!list_empty(&task->list));
list_insert_tail(&task->list, &global_tasks.list);
global_tasks.total++;
}
void l4lib_global_remove_task(struct l4lib_tcb *task)
{
BUG_ON(list_empty(&task->list));
list_remove_init(&task->list);
BUG_ON(--global_tasks.total < 0);
}
struct l4lib_tcb * l4lib_find_task(int tid)
{
struct l4lib_tcb *t;
list_foreach_struct(t, &global_tasks.list, list)
if (t->tid == tid)
return t;
return 0;
}
struct l4lib_tcb *l4_tcb_alloc_init(struct l4lib_tcb *parent, unsigned int flags)
{
struct l4lib_tcb *task;
if (!(task = kzalloc(sizeof(struct l4lib_tcb))))
return PTR_ERR(-ENOMEM);
link_init(&task->list);
if (flags & TC_SHARE_SPACE)
task->utcb_head = parent->utcb_head;
else {
/* COPY or NEW space */
if (!(task->utcb_head = kzalloc(sizeof(struct l4lib_utcb_head)))) {
kfree(task);
return PTR_ERR(-ENOMEM);
}
link_init(&task->utcb_head->list);
}
return task;
}

View File

@@ -1,210 +0,0 @@
/*
* Thread creation userspace helpers
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <stdio.h>
#include <malloc/malloc.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/arch/syslib.h>
#include <l4lib/exregs.h>
#include <l4lib/mutex.h>
#include <l4/api/thread.h>
#include <l4/api/errno.h>
#include <l4lib/thread/utcb-common.h>
#include <l4lib/thread/stack.h>
/* Extern declarations */
extern void setup_new_thread(void);
extern unsigned long lib_stack_size;
extern unsigned long lib_utcb_range_size;
/* Static variable definitions */
struct l4_mutex lib_mutex;
/* Function definitions */
int l4_thread_create(struct task_ids *ids, unsigned int flags,
int (*func)(void *), void *arg)
{
struct exregs_data exregs;
unsigned long utcb_addr;
struct l4lib_tcb *parent, *child;
unsigned long stack_top_addr, stack_bot_addr;
int err = 0;
/* A few controls before granting access to thread creation */
if (!IS_STACK_SETUP() || !IS_UTCB_SETUP()) {
printf("libl4thread: Stack and/or utcb have not been "
"set up.\n");
return -EPERM;
}
/* Before doing any operation get the global mutex. */
l4_mutex_lock(&lib_mutex);
/* Get parent's ids and find the l4lib_tcb belonging to it. */
l4_getid(ids);
if (!(parent = l4lib_find_task(ids->tid))) {
err = -ESRCH;
goto out_err1;
}
/* Allocate l4lib_tcb for the child. */
if (!(child = l4_tcb_alloc_init(parent, flags))) {
// FIXME: What happens to utcb_head
printf("libl4thread: No heap space left.\n");
err = -ENOMEM;
goto out_err1;
}
/* Get a utcb addr. */
if (!(utcb_addr = get_utcb_addr(child))) {
printf("libl4thread: No utcb space left.\n");
err = -ENOMEM;
goto out_err2;
}
/* Get a stack space and calculate the bottom addr of the stack. */
stack_top_addr = (unsigned long)get_stack_space();
if (!stack_top_addr) {
printf("libl4thread: No stack space left.\n");
err = -ENOMEM;
goto out_err3;
}
stack_bot_addr = stack_top_addr + lib_stack_size;
child->stack_addr = stack_top_addr;
/* Create thread */
if ((err = l4_thread_control(THREAD_CREATE | flags, ids)) < 0) {
printf("libl4thread: l4_thread_control(THREAD_CREATE) "
"failed with (%d).\n", err);
goto out_err4;
}
/* Setup new thread pc, sp, utcb */
memset(&exregs, 0, sizeof(exregs));
exregs_set_stack(&exregs, align((stack_bot_addr - 1), 8));
exregs_set_pc(&exregs, (unsigned long)setup_new_thread);
exregs_set_utcb(&exregs, (unsigned long)utcb_addr);
if ((err = l4_exchange_registers(&exregs, ids->tid)) < 0) {
printf("libl4thread: l4_exchange_registers failed with "
"(%d).\n", err);
goto out_err5;
}
/* First word of new stack is arg */
((unsigned long *)align((stack_bot_addr - 1), 8))[0] =
(unsigned long)arg;
/* Second word of new stack is function address */
((unsigned long *)align((stack_bot_addr - 1), 8))[-1] =
(unsigned long)func;
/* Add child to the global task list */
child->tid = ids->tid;
l4lib_global_add_task(child);
/* Start the new thread */
if ((err = l4_thread_control(THREAD_RUN, ids)) < 0) {
printf("libl4thread: l4_thread_control(THREAD_RUN) "
"failed with (%d).\n", err);
goto out_err6;
}
/* Release the global mutex. */
l4_mutex_unlock(&lib_mutex);
return 0;
/* Error handling. */
out_err6:
l4lib_global_remove_task(child);
out_err5:
l4_thread_control(THREAD_DESTROY, ids);
out_err4:
delete_stack_space((void *)child->stack_addr);
out_err3:
delete_utcb_addr(child);
out_err2:
if ((flags & TC_COPY_SPACE) || (flags & TC_NEW_SPACE))
kfree(child->utcb_head);
kfree(child);
out_err1:
l4_mutex_unlock(&lib_mutex);
return err;
}
void l4_thread_exit(int retval)
{
struct l4lib_tcb *task;
struct task_ids ids;
/* Before doing any operation get the global mutex. */
l4_mutex_lock(&lib_mutex);
/* Find the task. */
l4_getid(&ids);
/* Cant find the thread means it wasnt added to the list. */
if (!(task = l4lib_find_task(ids.tid)))
BUG();
/* Remove child from the global task list. */
l4lib_global_remove_task(task);
/* Delete the stack space. */
if (delete_stack_space((void *)task->stack_addr) < 0)
BUG();
/* Delete the utcb address. */
delete_utcb_addr(task);
// FIXME: We assume that main thread never leaves the scene
// FIXME: What happens to task->utcb_head?
kfree(task);
/* Release the global mutex. */
l4_mutex_unlock(&lib_mutex);
/* Relinquish the control. */
l4_exit(retval);
/* Should never reach here. */
BUG();
}
int l4_thread_kill(struct task_ids *ids)
{
struct l4lib_tcb *task;
/* Before doing any operation get the global mutex. */
l4_mutex_lock(&lib_mutex);
/* Find the task to be killed. */
if (!(task = l4lib_find_task(ids->tid))) {
l4_mutex_unlock(&lib_mutex);
return -ESRCH;
}
/* Remove child from the global task list. */
l4lib_global_remove_task(task);
/* Delete the stack space. */
if (delete_stack_space((void *)task->stack_addr) < 0)
BUG();
/* Delete the utcb address. */
delete_utcb_addr(task);
// FIXME: We assume that main thread never leaves the scene
// FIXME: What happens to task->utcb_head?
kfree(task);
/* Release the global mutex. */
l4_mutex_unlock(&lib_mutex);
/* Finally, destroy the thread. */
l4_thread_control(THREAD_DESTROY, ids);
return 0;
}

View File

@@ -1,94 +0,0 @@
/*
* UTCB management in libl4thread.
*
* Copyright © 2009 B Labs Ltd.
*/
#include <stdio.h>
#include <l4lib/addr.h>
#include <l4lib/thread/utcb-common.h>
#include <malloc/malloc.h>
#include INC_GLUE(message.h)
/* Globally disjoint utcb virtual region pool */
static struct address_pool utcb_region_pool;
int utcb_pool_init(unsigned long utcb_start, unsigned long utcb_end)
{
int err;
/* Initialise the global utcb virtual address pool */
if ((err = address_pool_init(&utcb_region_pool,
utcb_start, utcb_end,
PAGE_SIZE) < 0)) {
printf("UTCB address pool initialisation failed.\n");
return err;
}
return 0;
}
static inline void *utcb_new_address(int nitems)
{
return address_new(&utcb_region_pool, nitems, PAGE_SIZE);
}
static inline int utcb_delete_address(void *utcb_address, int nitems)
{
return address_del(&utcb_region_pool, utcb_address, nitems, PAGE_SIZE);
}
/* Return an empty utcb slot in this descriptor */
unsigned long utcb_new_slot(struct l4lib_utcb_desc *desc)
{
int slot;
if ((slot = id_new(desc->slots)) < 0)
return 0;
else
return desc->utcb_base + (unsigned long)slot * UTCB_SIZE;
}
int utcb_delete_slot(struct l4lib_utcb_desc *desc, unsigned long address)
{
BUG_ON(id_del(desc->slots, (address - desc->utcb_base)
/ UTCB_SIZE) < 0);
return 0;
}
struct l4lib_utcb_desc *utcb_new_desc(void)
{
struct l4lib_utcb_desc *d;
/* Allocate a new descriptor */
if (!(d = kzalloc(sizeof(*d))))
return 0;
link_init(&d->list);
/* We currently assume UTCB is smaller than PAGE_SIZE */
BUG_ON(UTCB_SIZE > PAGE_SIZE);
/* Initialise utcb slots */
d->slots = id_pool_new_init(PAGE_SIZE / UTCB_SIZE);
/* Obtain a new and unique utcb base */
/* FIXME: Use variable size than a page */
if (!(d->utcb_base = (unsigned long)utcb_new_address(1))) {
kfree(d->slots);
kfree(d);
return 0;
}
return d;
}
int utcb_delete_desc(struct l4lib_utcb_desc *desc)
{
/* Return descriptor address */
utcb_delete_address((void *)desc->utcb_base, 1);
/* Free the descriptor */
kfree(desc);
return 0;
}

View File

@@ -1,162 +0,0 @@
/*
* UTCB handling helper routines.
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <stdio.h>
#include <malloc/malloc.h>
#include <l4/api/errno.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/exregs.h>
#include <l4lib/idpool.h>
#include <l4lib/thread/utcb-common.h>
#include <l4lib/utcb.h>
/* Extern declarations */
extern struct l4lib_global_list global_tasks;
/* Global variables */
unsigned long lib_utcb_range_size;
/* Function definitions */
unsigned long get_utcb_addr(struct l4lib_tcb *task)
{
struct l4lib_utcb_desc *udesc;
unsigned long slot;
/* Setting this up twice is a bug. */
BUG_ON(task->utcb_addr);
/* Search for an empty utcb slot already allocated to this space. */
list_foreach_struct(udesc, &task->utcb_head->list, list)
if ((slot = utcb_new_slot(udesc)))
goto found;
/* Allocate a new utcb memory region and return its base. */
if (!(udesc = utcb_new_desc()))
return 0;
slot = utcb_new_slot(udesc);
list_insert(&udesc->list, &task->utcb_head->list);
found:
task->utcb_addr = slot;
return slot;
}
int delete_utcb_addr(struct l4lib_tcb *task)
{
struct l4lib_utcb_desc *udesc;
list_foreach_struct(udesc, &task->utcb_head->list, list) {
/* FIXME: Use variable alignment than a page */
/* Detect matching slot */
if (page_align(task->utcb_addr) == udesc->utcb_base) {
/* Delete slot from the descriptor */
utcb_delete_slot(udesc, task->utcb_addr);
/* Is the desc completely empty now? */
if (id_is_empty(udesc->slots)) {
/* Unlink desc from its list */
list_remove_init(&udesc->list);
/* Delete the descriptor */
utcb_delete_desc(udesc);
}
return 0; /* Finished */
}
}
BUG();
}
static int set_utcb_addr(void)
{
struct exregs_data exregs;
struct task_ids ids;
struct l4lib_tcb *task;
struct l4lib_utcb_desc *udesc;
int err;
/* Create a task. */
if (IS_ERR(task = l4_tcb_alloc_init(0, 0)))
return -ENOMEM;
/* Add child to the global task list. */
list_insert_tail(&task->list, &global_tasks.list);
global_tasks.total++;
if (!(udesc = utcb_new_desc()))
return -ENOMEM;
task->utcb_addr = utcb_new_slot(udesc);
list_insert(&udesc->list, &task->utcb_head->list);
memset(&exregs, 0, sizeof(exregs));
exregs_set_utcb(&exregs, task->utcb_addr);
l4_getid(&ids);
task->tid = ids.tid;
if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) {
printf("libl4thread: l4_exchange_registers failed with "
"(%d).\n", err);
return err;
}
return 0;
}
int l4_set_utcb_params(unsigned long utcb_start, unsigned long utcb_end)
{
int err;
/* Ensure that arguments are valid. */
if (IS_UTCB_SETUP()) {
printf("libl4thread: You have already called: %s.\n",
__FUNCTION__);
return -EPERM;
}
if (!utcb_start || !utcb_end) {
printf("libl4thread: Utcb address range cannot contain "
"0x0 as a start and/or end address(es).\n");
return -EINVAL;
}
/* Check if the start address is aligned on PAGE_SIZE. */
if (utcb_start & PAGE_MASK) {
printf("libl4thread: Utcb start address must be aligned "
"on PAGE_SIZE(0x%x).\n", PAGE_SIZE);
return -EINVAL;
}
/* The range must be a valid one. */
if (utcb_start >= utcb_end) {
printf("libl4thread: Utcb end address must be bigger "
"than utcb start address.\n");
return -EINVAL;
}
#if 0
/*
* This check guarantees two things:
* 1. The range must be multiple of UTCB_SIZE, at least one item.
* 2. utcb_end is aligned on UTCB_SIZE.
*/
if ((utcb_end - utcb_start) % UTCB_SIZE) {
printf("libl4thread: The given range size must be multiple "
"of the utcb size(%d).\n", UTCB_SIZE);
return -EINVAL;
}
#endif
/* Arguments passed the validity tests. */
/* Init utcb virtual address pool. */
if (utcb_pool_init(utcb_start, utcb_end) < 0)
BUG();
/*
* The very first thread's utcb address is assigned.
* It should not return an error value.
*/
if ((err = set_utcb_addr()) < 0)
BUG();
/* Initialize internal variables. */
lib_utcb_range_size = utcb_end - utcb_start;
return 0;
}

View File

@@ -155,9 +155,12 @@ struct mem_cache *mem_cache_init(void *start,
if (total & 0x1F) { /* Remainder? */
bwords++; /* Add one more word for remainder */
}
bsize = bwords * 4;
/* This many structures will be chucked from cache for bitmap space */
bwords_in_structs = ((bsize) / struct_size) + 1;
/* Total structs left after deducing bitmaps */
total = total - bwords_in_structs;
cache_size -= bsize;

View File

@@ -1,14 +0,0 @@
#ifndef __INITTASK_ARCH_MM_H__
#define __INITTASK_ARCH_MM_H__
#include <l4/macros.h>
#include <l4/types.h>
#include INC_GLUE(memory.h)
#include <vm_area.h>
struct fault_data;
unsigned int vm_prot_flags(pte_t pte);
void set_generic_fault_params(struct fault_data *fault);
void fault_handle_error(struct fault_data *fault);
#endif /* __INITTASK_ARCH_MM_H__ */

View File

@@ -1,94 +0,0 @@
/*
* 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.
*/
#ifdef __thumb__
#define bl blx
#endif
.section .text.head
.code 32
.global _start;
.align;
_start:
ldr sp, =__stack
bl platform_init
bl __container_init
1:
b 1b

View File

@@ -1,84 +0,0 @@
/*
* Copyright (C) 2007 Bahadir Balban
*/
#include <arch/mm.h>
#include <task.h>
#include <vm_area.h>
#include <l4lib/exregs.h>
/* Extracts generic protection flags from architecture-specific pte */
unsigned int vm_prot_flags(pte_t pte)
{
unsigned int vm_prot_flags = 0;
unsigned int rw_flags = __MAP_USR_RW_FLAGS & PTE_PROT_MASK;
unsigned int ro_flags = __MAP_USR_RO_FLAGS & PTE_PROT_MASK;
/* Clear non-protection flags */
pte &= PTE_PROT_MASK;;
if (pte == ro_flags)
vm_prot_flags = VM_READ | VM_EXEC;
else if (pte == rw_flags)
vm_prot_flags = VM_READ | VM_WRITE | VM_EXEC;
else
vm_prot_flags = VM_NONE;
return vm_prot_flags;
}
#if defined(DEBUG_FAULT_HANDLING)
void arch_print_fault_params(struct fault_data *fault)
{
printf("%s: Handling %s fault (%s abort) from %d. fault @ 0x%x\n",
__TASKNAME__, (fault->reason & VM_READ) ? "read" : "write",
is_prefetch_abort(fault->kdata->fsr) ? "prefetch" : "data",
fault->task->tid, fault->address);
}
#else
void arch_print_fault_params(struct fault_data *fault) { }
#endif
void fault_handle_error(struct fault_data *fault)
{
struct task_ids ids;
/* Suspend the task */
ids.tid = fault->task->tid;
BUG_ON(l4_thread_control(THREAD_SUSPEND, &ids) < 0);
BUG();
}
/*
* PTE STATES:
* PTE type field: 00 (Translation fault)
* PTE type field correct, AP bits: None (Read or Write access fault)
* PTE type field correct, AP bits: RO (Write access fault)
*/
/* Extracts arch-specific fault parameters and puts them into generic format */
void set_generic_fault_params(struct fault_data *fault)
{
unsigned int prot_flags = vm_prot_flags(fault->kdata->pte);
fault->reason = 0;
fault->pte_flags = prot_flags;
if (is_prefetch_abort(fault->kdata->fsr)) {
fault->reason |= VM_READ;
fault->address = fault->kdata->faulty_pc;
} else {
fault->address = fault->kdata->far;
/* Always assume read fault first */
if (prot_flags & VM_NONE)
fault->reason |= VM_READ;
else if (prot_flags & VM_READ)
fault->reason |= VM_WRITE;
else
BUG();
}
arch_print_fault_params(fault);
}

View File

@@ -1,22 +0,0 @@
#ifndef __LINKER_H__
#define __LINKER_H__
/*
*
* Mock-up copies of variables defined in linker.h
*
* Copyright (C) 2005 Bahadir Balban
*
*/
/* Because no special-case linker.lds is used for tests,
* actual values for these variables are stored in a linker.c
*/
/* Global that determines where free memory starts.
* Normally this is the end address of the kernel image
* in physical memory when it is loaded. See linker.h
* for other architectures.
*/
extern unsigned int _end;
#endif /* __LINKER_H__ */

View File

@@ -1,68 +0,0 @@
/*
* ARM v5-specific virtual memory details
*
* Copyright (C) 2005 Bahadir Balban
*/
#ifndef __V5__MM__H__
#define __V5__MM__H__
/* TODO: Change all LEVEL1_ prefix to PGD and
* shorten the macros in general */
#define LEVEL1_PAGETABLE_SIZE SZ_4K * 4
#define LEVEL1_PAGETABLE_NUMENT SZ_4K
#define LEVEL1_PTE_TYPE_MASK 0x3
#define LEVEL1_COARSE_ALIGN_MASK 0xFFFFFC00
#define LEVEL1_SECTION_ALIGN_MASK 0xFFF00000
#define LEVEL1_FINE_ALIGN_MASK 0xFFFFF000
#define LEVEL1_TYPE_FAULT 0
#define LEVEL1_TYPE_COARSE 1
#define LEVEL1_TYPE_SECTION 2
#define LEVEL1_TYPE_FINE 3
#define LEVEL2_TYPE_FAULT 0
#define LEVEL2_TYPE_LARGE 1
#define LEVEL2_TYPE_SMALL 2
#define LEVEL2_TYPE_TINY 3
/* Permission field offsets */
#define SECTION_AP0 10
#define PMD_SIZE SZ_1K
#define PMD_NUM_PAGES 256
/* Applies for both small and large pages */
#define PAGE_AP0 4
#define PAGE_AP1 6
#define PAGE_AP2 8
#define PAGE_AP3 10
/* Permission values with rom and sys bits ignored */
#define SVC_RW_USR_NONE 1
#define SVC_RW_USR_RO 2
#define SVC_RW_USR_RW 3
#define CACHEABILITY 3
#define BUFFERABILITY 4
#define cacheable (1 << CACHEABILITY)
#define bufferable (1 << BUFFERABILITY)
static inline void
__add_section_mapping_init(unsigned int paddr, unsigned int vaddr,
unsigned int size, unsigned int flags)
{
}
static inline void
add_section_mapping_init(unsigned int paddr, unsigned int vaddr,
unsigned int size, unsigned int flags)
{
}
static inline void
add_mapping(unsigned int paddr, unsigned int vaddr,
unsigned int size, unsigned int flags)
{
}
static inline void remove_mapping(unsigned int vaddr)
{
}
#endif /* __V5__MM__H__ */

View File

@@ -1,13 +0,0 @@
#ifndef __ARCH__ARM__TYPES_H__
#define __ARCH__ARM__TYPES_H__
typedef unsigned long long u64;
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef signed long long s64;
typedef signed int s32;
typedef signed short s16;
typedef signed char s8;
#endif /* !__ARCH__ARM__TYPES_H__ */

View File

@@ -1,54 +0,0 @@
/*
* SP810 Primecell system controller offsets
*
* Copyright (C) 2007 Bahadir Balban
*
*/
#ifndef __SP810_SYSCTRL_H__
#define __SP810_SYSCTRL_H__
#include INC_PLAT(platform.h)
/* FIXME: Fix the stupid uart driver and change to single definition of this! */
#if defined(read)
#undef read
#endif
#if defined(write)
#undef write
#endif
#define read(a) *((volatile unsigned int *)(a))
#define write(v, a) (*((volatile unsigned int *)(a)) = v)
#define setbit(bit, a) write(read(a) | bit, a)
#define clrbit(bit, a) write(read(a) & ~bit, a)
#define devio(base, reg, bit, setclr) \
(setclr) ? setbit(bit, base + reg) \
: clrbit(bit, base + reg)
/* The SP810 system controller offsets */
#define SP810_BASE PLATFORM_SYSCTRL_VIRTUAL
#define SP810_SCCTRL (SP810_BASE + 0x0)
/* ... Fill in as needed. */
/* Set clock source for timers on this platform.
* @timer: The index of timer you want to set the clock for.
* On PB926 valid values are 0-4.
*
* @freq: The frequency you want to set the timer for.
* On PB926 valid values are 32KHz = 0 (0 is 32Khz because that's
* the default.) and 1MHz = non-zero.
*/
static inline void sp810_set_timclk(int timer, unsigned int freq)
{
if (timer < 0 || timer > 3)
return;
freq ? setbit((1 << (15 + (2 * timer))), SP810_SCCTRL) :
clrbit((1 << (15 + (2 * timer))), SP810_SCCTRL);
return;
}
#endif /* __SP810_SYSCTRL_H__ */

View File

@@ -1,43 +0,0 @@
/*
* SP804 Primecell Timer offsets
*
* Copyright (C) 2007 Bahadir Balban
*
*/
#ifndef __SP804_TIMER_H__
#define __SP804_TIMER_H__
#include INC_PLAT(platform.h)
/* Run mode of timers */
#define SP804_TIMER_RUNMODE_FREERUN 0
#define SP804_TIMER_RUNMODE_PERIODIC 1
/* Wrap mode of timers */
#define SP804_TIMER_WRAPMODE_WRAPPING 0
#define SP804_TIMER_WRAPMODE_ONESHOT 1
/* Operational width of timer */
#define SP804_TIMER_WIDTH16BIT 0
#define SP804_TIMER_WIDTH32BIT 1
/* Enable/disable irq on timer */
#define SP804_TIMER_IRQDISABLE 0
#define SP804_TIMER_IRQENABLE 1
/* Register offsets */
#define SP804_TIMERLOAD 0x0
#define SP804_TIMERVALUE 0x4
#define SP804_TIMERCONTROL 0x8
#define SP804_TIMERINTCLR 0xC
#define SP804_TIMERRIS 0x10
#define SP804_TIMERMIS 0x14
#define SP804_TIMERBGLOAD 0x18
void sp804_init(unsigned int timer_base, int runmode, int wrapmode, \
int width, int irq_enable);
void sp804_irq_handler(unsigned int timer_base);
void sp804_enable(unsigned int timer_base, int enable);
void sp804_set_irq(unsigned int timer_base, int enable);
#endif /* __SP804_TIMER_H__ */

View File

@@ -1,344 +0,0 @@
/*
* PL011 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 __PL011_UART_H__
#define __PL011_UART_H__
#include INC_PLAT(uart.h)
#include INC_ARCH(io.h)
/* 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)
struct pl011_uart;
void pl011_initialise_driver();
int pl011_initialise_device(struct pl011_uart * uart);
int pl011_tx_char(unsigned int base, char c);
int pl011_rx_char(unsigned int base, char *c);
void pl011_set_baudrate(unsigned int base, unsigned int baud, \
unsigned int clkrate);
void pl011_set_irq_mask(unsigned int base, unsigned int flags);
void pl011_clr_irq_mask(unsigned int base, unsigned int flags);
void pl011_irq_handler(struct pl011_uart * uart);
void pl011_tx_irq_handler(struct pl011_uart * uart, unsigned int flags);
void pl011_rx_irq_handler(struct pl011_uart *uart, unsigned int flags);
void pl011_error_irq_handler(struct pl011_uart *uart, unsigned int flags);
struct pl011_uart {
unsigned int base;
unsigned int frame_errors;
unsigned int parity_errors;
unsigned int break_errors;
unsigned int overrun_errors;
unsigned int rx_timeout_errors;
};
#define PL011_UARTEN (1 << 0)
static inline void pl011_uart_enable(unsigned int uart_base)
{
unsigned int val;
val = 0;
read(val, (uart_base + PL011_UARTCR));
val |= PL011_UARTEN;
write(val, (uart_base + PL011_UARTCR));
return;
}
static inline void pl011_uart_disable(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTCR));
val &= ~PL011_UARTEN;
write(val, (uart_base + PL011_UARTCR));
return;
}
#define PL011_TXE (1 << 8)
static inline void pl011_tx_enable(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTCR));
val |= PL011_TXE;
write(val, (uart_base + PL011_UARTCR));
return;
}
static inline void pl011_tx_disable(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTCR));
val &= ~PL011_TXE;
write(val, (uart_base + PL011_UARTCR));
return;
}
#define PL011_RXE (1 << 9)
static inline void pl011_rx_enable(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTCR));
val |= PL011_RXE;
write(val, (uart_base + PL011_UARTCR));
return;
}
static inline void pl011_rx_disable(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTCR));
val &= ~PL011_RXE;
write(val, (uart_base + PL011_UARTCR));
return;
}
#define PL011_TWO_STOPBITS_SELECT (1 << 3)
static inline void pl011_set_stopbits(unsigned int uart_base, int stopbits)
{
unsigned int val = 0;
read(val, (uart_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, (uart_base + PL011_UARTLCR_H));
return;
}
#define PL011_PARITY_ENABLE (1 << 1)
static inline void pl011_parity_enable(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTLCR_H));
val |= PL011_PARITY_ENABLE;
write(val, (uart_base + PL011_UARTLCR_H));
return;
}
static inline void pl011_parity_disable(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTLCR_H));
val &= ~PL011_PARITY_ENABLE;
write(val, (uart_base + PL011_UARTLCR_H));
return;
}
#define PL011_PARITY_EVEN (1 << 2)
static inline void pl011_set_parity_even(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTLCR_H));
val |= PL011_PARITY_EVEN;
write(val, (uart_base + PL011_UARTLCR_H));
return;
}
static inline void pl011_set_parity_odd(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTLCR_H));
val &= ~PL011_PARITY_EVEN;
write(val, (uart_base + PL011_UARTLCR_H));
return;
}
#define PL011_ENABLE_FIFOS (1 << 4)
static inline void pl011_enable_fifos(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTLCR_H));
val |= PL011_ENABLE_FIFOS;
write(val, (uart_base + PL011_UARTLCR_H));
return;
}
static inline void pl011_disable_fifos(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTLCR_H));
val &= ~PL011_ENABLE_FIFOS;
write(val, (uart_base + PL011_UARTLCR_H));
return;
}
#define PL011_WORD_WIDTH_SHIFT (5)
/* Sets the transfer word width for the data register. */
static inline void pl011_set_word_width(unsigned int uart_base, int size)
{
unsigned int val = 0;
if(size < 5 || size > 8) /* Default is 8 */
size = 8;
/* Clear size field */
read(val, (uart_base + PL011_UARTLCR_H));
val &= ~(0x3 << PL011_WORD_WIDTH_SHIFT);
write(val, (uart_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
*/
read(val, (uart_base + PL011_UARTLCR_H));
val |= (size - 5) << PL011_WORD_WIDTH_SHIFT;
write(val, (uart_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 int uart_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), (uart_base + PL011_UARTIFLS));
return;
}
/* returns which irqs are masked */
static inline unsigned int pl011_read_irqmask(unsigned int uart_base)
{
unsigned int flags;
read(flags, (uart_base + PL011_UARTIMSC));
return flags;
}
/* returns masked irq status */
static inline unsigned int pl011_read_irqstat(unsigned int uart_base)
{
unsigned int irqstatus;
read(irqstatus, (uart_base + PL011_UARTMIS));
return irqstatus;
}
/* Clears the given asserted irqs */
static inline void pl011_irq_clear(unsigned int uart_base, unsigned int flags)
{
if(flags > 0x3FF) { /* Invalid irq clearing bitvector */
return;
}
/* Simply write the flags since it's a write-only register */
write(flags, (uart_base + PL011_UARTICR));
return;
}
#define PL011_TXDMAEN (1 << 1)
#define PL011_RXDMAEN (1 << 0)
/* Enables dma transfers for uart. The dma controller
* must be initialised, set-up and enabled separately.
*/
static inline void pl011_tx_dma_enable(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTDMACR));
val |= PL011_TXDMAEN;
write(val, (uart_base + PL011_UARTDMACR));
return;
}
/* Disables dma transfers for uart */
static inline void pl011_tx_dma_disable(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTDMACR));
val &= ~PL011_TXDMAEN;
write(val, (uart_base + PL011_UARTDMACR));
return;
}
static inline void pl011_rx_dma_enable(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTDMACR));
val |= PL011_RXDMAEN;
write(val, (uart_base + PL011_UARTDMACR));
return;
}
static inline void pl011_rx_dma_disable(unsigned int uart_base)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTDMACR));
val &= ~PL011_RXDMAEN;
write(val, (uart_base + PL011_UARTDMACR));
return;
}
#endif /* __PL011_UART__ */

View File

@@ -1,15 +0,0 @@
#ifndef __PLATFORM__PB926__PRINTASCII__H__
#define __PLATFORM__PB926__PRINTASCII__H__
#define dprintk(str, val) \
{ \
printascii(str); \
printascii("0x"); \
printhex8((val)); \
printascii("\n"); \
}
void printascii(char *str);
void printhex8(unsigned int);
#endif /* __PLATFORM__PB926__PRINTASCII__H__ */

View File

@@ -1,388 +0,0 @@
/*
* Memory exception handling in process context.
*
* Copyright (C) 2007, 2008 Bahadir Balban
*/
#include <l4/generic/scheduler.h>
#include <l4/generic/thread.h>
#include <l4/api/thread.h>
#include <l4/generic/space.h>
#include <l4/generic/tcb.h>
#include <l4/lib/printk.h>
#include <l4/api/ipc.h>
#include <l4/api/kip.h>
#include <l4/api/errno.h>
#include INC_PLAT(printascii.h)
#include INC_ARCH(exception.h)
#include INC_GLUE(memlayout.h)
#include INC_GLUE(memory.h)
#include INC_GLUE(message.h)
#include INC_GLUE(ipc.h)
#include INC_SUBARCH(mm.h)
/* Abort debugging conditions */
// #define DEBUG_ABORTS
#if defined (DEBUG_ABORTS)
#define dbg_abort(...) dprintk(__VA_ARGS__)
#else
#define dbg_abort(...)
#endif
struct ipc_state {
u32 mr[MR_TOTAL];
unsigned int flags;
};
void ipc_save_state(struct ipc_state *state)
{
unsigned int *mr0_current = KTCB_REF_MR0(current);
BUG_ON(!mr0_current);
/* Save primary message registers */
for (int i = 0; i < MR_TOTAL; i++)
state->mr[i] = mr0_current[i];
/* Save ipc flags */
state->flags = tcb_get_ipc_flags(current);
}
void ipc_restore_state(struct ipc_state *state)
{
unsigned int *mr0_current = KTCB_REF_MR0(current);
BUG_ON(!mr0_current);
/* Restore primary message registers */
for (int i = 0; i < MR_TOTAL; i++)
mr0_current[i] = state->mr[i];
/* Restore ipc flags */
tcb_set_ipc_flags(current, state->flags);
}
/* Send data fault ipc to the faulty task's pager */
int fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far, u32 ipc_tag)
{
int err;
/* mr[0] has the fault tag. The rest is the fault structure */
u32 mr[MR_TOTAL] = {
[MR_TAG] = ipc_tag,
[MR_SENDER] = current->tid
};
fault_kdata_t *fault = (fault_kdata_t *)&mr[MR_UNUSED_START];
/* Fill in fault information to pass over during ipc */
fault->faulty_pc = faulty_pc;
fault->fsr = fsr;
fault->far = far;
/*
* Write pte of the abort address,
* which is different on pabt/dabt
*/
if (is_prefetch_abort(fsr))
fault->pte = virt_to_pte(faulty_pc);
else
fault->pte = virt_to_pte(far);
/*
* System calls save arguments (and message registers)
* on the kernel stack. They are then referenced from
* the caller's ktcb. Here, we forge a fault structure
* as if an ipc syscall has occured. Then the reference
* to the fault structure is set in the ktcb such that
* it lies on the mr0 offset when referred as the syscall
* context.
*/
/*
* Assign fault such that it overlaps
* as the MR0 reference in ktcb.
*/
current->syscall_regs = (syscall_context_t *)
((unsigned long)&mr[0] -
offsetof(syscall_context_t, r3));
/* Set current flags to short ipc */
tcb_set_ipc_flags(current, IPC_FLAGS_SHORT);
/* Detect if a pager is self-faulting */
if (current->tid == current->pagerid) {
printk("Pager (%d) faulted on itself. FSR: 0x%x, FAR: 0x%x, PC: 0x%x Exiting.\n",
current->tid, fault->fsr, fault->far, fault->faulty_pc);
thread_destroy(current);
}
/* Send ipc to the task's pager */
if ((err = ipc_sendrecv(current->pagerid,
current->pagerid, 0)) < 0) {
BUG_ON(current->nlocks);
/* Return on interrupt */
if (err == -EINTR) {
printk("Thread (%d) page-faulted "
"and got interrupted by its pager.\n",
current->tid);
return err;
} else { /* Suspend on any other error */
printk("Thread (%d) faulted in kernel "
"and an error occured during "
"page-fault ipc. err=%d. Suspending task.\n",
current->tid, err);
current->flags |= TASK_SUSPENDING;
sched_suspend_sync();
}
}
return 0;
}
/*
* When a task calls the kernel and the supplied user buffer is
* not mapped, the kernel generates a page fault to the task's
* pager so that the pager can make the decision on mapping the
* buffer. Remember that if a task maps its own user buffer to
* itself this way, the kernel can access it, since it shares
* that task's page table.
*/
int pager_pagein_request(unsigned long addr, unsigned long size,
unsigned int flags)
{
int err;
u32 abort = 0;
unsigned long npages = __pfn(align_up(size, PAGE_SIZE));
struct ipc_state ipc_state;
set_abort_type(abort, ARM_DABT);
// printk("%s: Kernel initiating paging-in requests\n", __FUNCTION__);
/* Save current ipc state */
ipc_save_state(&ipc_state);
/* For every page to be used by the kernel send a page-in request */
for (int i = 0; i < npages; i++)
if ((err = fault_ipc_to_pager(0, abort,
addr + (i * PAGE_SIZE),
L4_IPC_TAG_PFAULT)) < 0)
return err;
/* Restore ipc state */
ipc_restore_state(&ipc_state);
return 0;
}
int check_aborts(u32 faulted_pc, u32 fsr, u32 far)
{
int ret = 0;
if (is_prefetch_abort(fsr)) {
dbg_abort("Prefetch abort @ ", faulted_pc);
return 0;
}
switch (fsr & ARM_FSR_MASK) {
/* Aborts that are expected on page faults: */
case DABT_PERM_PAGE:
dbg_abort("Page permission fault @ ", far);
ret = 0;
break;
case DABT_XLATE_PAGE:
dbg_abort("Page translation fault @ ", far);
ret = 0;
break;
case DABT_XLATE_SECT:
dbg_abort("Section translation fault @ ", far);
ret = 0;
break;
/* Aborts that can't be handled by a pager yet: */
case DABT_TERMINAL:
dprintk("Terminal fault dabt @ ", far);
ret = -EINVAL;
break;
case DABT_VECTOR:
dprintk("Vector abort (obsolete!) @ ", far);
ret = -EINVAL;
break;
case DABT_ALIGN:
dprintk("Alignment fault dabt @ ", far);
ret = -EINVAL;
break;
case DABT_EXT_XLATE_LEVEL1:
dprintk("External LVL1 translation fault @ ", far);
ret = -EINVAL;
break;
case DABT_EXT_XLATE_LEVEL2:
dprintk("External LVL2 translation fault @ ", far);
ret = -EINVAL;
break;
case DABT_DOMAIN_SECT:
dprintk("Section domain fault dabt @ ", far);
ret = -EINVAL;
break;
case DABT_DOMAIN_PAGE:
dprintk("Page domain fault dabt @ ", far);
ret = -EINVAL;
break;
case DABT_PERM_SECT:
dprintk("Section permission fault dabt @ ", far);
ret = -EINVAL;
break;
case DABT_EXT_LFETCH_SECT:
dprintk("External section linefetch fault dabt @ ", far);
ret = -EINVAL;
break;
case DABT_EXT_LFETCH_PAGE:
dprintk("Page perm fault dabt @ ", far);
ret = -EINVAL;
break;
case DABT_EXT_NON_LFETCH_SECT:
dprintk("External section non-linefetch fault dabt @ ", far);
ret = -EINVAL;
break;
case DABT_EXT_NON_LFETCH_PAGE:
dprintk("External page non-linefetch fault dabt @ ", far);
ret = -EINVAL;
break;
default:
dprintk("FATAL: Unrecognised/Unknown data abort @ ", far);
dprintk("FATAL: FSR code: ", fsr);
ret = -EINVAL;
}
return ret;
}
/*
* @r0: The address where the program counter was during the fault.
* @r1: Contains the fault status register
* @r2: Contains the fault address register
*/
void data_abort_handler(u32 faulted_pc, u32 fsr, u32 far)
{
set_abort_type(fsr, ARM_DABT);
dbg_abort("Data abort @ PC: ", faulted_pc);
//printk("Data abort: %d, PC: 0x%x\n", current->tid, faulted_pc);
/* Check for more details */
if (check_aborts(faulted_pc, fsr, far) < 0) {
printascii("This abort can't be handled by any pager.\n");
goto error;
}
if (KERN_ADDR(faulted_pc))
goto error;
/* This notifies the pager */
fault_ipc_to_pager(faulted_pc, fsr, far, L4_IPC_TAG_PFAULT);
if (current->flags & TASK_SUSPENDING) {
BUG_ON(current->nlocks);
sched_suspend_sync();
} else if (current->flags & TASK_EXITING) {
BUG_ON(current->nlocks);
sched_exit_sync();
}
return;
error:
disable_irqs();
dprintk("Unhandled data abort @ PC address: ", faulted_pc);
dprintk("FAR:", far);
dprintk("FSR:", fsr);
printascii("Kernel panic.\n");
printascii("Halting system...\n");
while (1)
;
}
void prefetch_abort_handler(u32 faulted_pc, u32 fsr, u32 far, u32 lr)
{
set_abort_type(fsr, ARM_PABT);
if (check_aborts(faulted_pc, fsr, far) < 0) {
printascii("This abort can't be handled by any pager.\n");
goto error;
}
if (KERN_ADDR(lr))
goto error;
fault_ipc_to_pager(faulted_pc, fsr, far, L4_IPC_TAG_PFAULT);
if (current->flags & TASK_SUSPENDING) {
BUG_ON(current->nlocks);
sched_suspend_sync();
} else if (current->flags & TASK_EXITING) {
BUG_ON(current->nlocks);
sched_exit_sync();
}
return;
error:
disable_irqs();
dprintk("Unhandled prefetch abort @ address: ", faulted_pc);
dprintk("FAR:", far);
dprintk("FSR:", fsr);
dprintk("LR:", lr);
printascii("Kernel panic.\n");
printascii("Halting system...\n");
while (1)
;
}
void undef_handler(u32 undef_addr, u32 spsr, u32 lr)
{
dbg_abort("Undefined instruction @ PC: ", undef_addr);
//printk("Undefined instruction: tid: %d, PC: 0x%x, Mode: %s\n",
// current->tid, undef_addr,
// (spsr & ARM_MODE_MASK) == ARM_MODE_SVC ? "SVC" : "User");
if (KERN_ADDR(lr)) {
printk("Panic: Undef in Kernel\n");
goto error;
}
fault_ipc_to_pager(undef_addr, 0, undef_addr, L4_IPC_TAG_UNDEF_FAULT);
if (current->flags & TASK_SUSPENDING) {
BUG_ON(current->nlocks);
sched_suspend_sync();
} else if (current->flags & TASK_EXITING) {
BUG_ON(current->nlocks);
sched_exit_sync();
}
return;
error:
disable_irqs();
dprintk("SPSR:", spsr);
dprintk("LR:", lr);
printascii("Kernel panic.\n");
printascii("Halting system...\n");
BUG();
}
extern int current_irq_nest_count;
/*
* This is called right where the nest count is increased
* in case the nesting is beyond the predefined max limit.
* It is another matter whether this limit is enough to
* guarantee the kernel stack is not overflown.
*/
void irq_overnest_error(void)
{
dprintk("Irqs nested beyond limit. Current count: ",
current_irq_nest_count);
printascii("Halting system...\n");
while(1)
;
}

View File

@@ -1,43 +0,0 @@
#include INC_ARCH(asm.h)
/*
* r0 = unsigned long *state, stores current irq state.
*/
BEGIN_PROC(irq_local_disable_save)
mov r1, r0 @ Move address of state to r1
mrs r2, cpsr_fc @ Read cpsr
orr r3, r2, #0x80 @ Disable irq bit in cpsr
msr cpsr_fc, r3 @ Write to cpsr
str r2, [r1] @ Store original cpsr in r2 to state
mov pc, lr
END_PROC(irq_local_disable_save)
/*
* r0 = last cpsr state
*/
BEGIN_PROC(irq_local_restore)
msr cpsr_fc, r0 @ Write r0 to cpsr
mov pc, lr
END_PROC(irq_local_restore)
/*
* r0 = byte address to read from.
*/
BEGIN_PROC(l4_atomic_dest_readb)
mov r1, r0 @ Move byte address to r1
mov r2, #0 @ Move 0 to r2
swpb r0, r2, [r1] @ Write 0 to byte location, while reading its value to r0
mov pc, lr @ Return byte location value
END_PROC(l4_atomic_dest_readb)
BEGIN_PROC(irqs_enabled)
mrs r1, cpsr_fc
tst r1, #0x80
moveq r0, #1
movne r0, #0
mov pc, lr
END_PROC(irqs_enabled)

View File

@@ -1,726 +0,0 @@
/*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/lib/printk.h>
#include <l4/lib/mutex.h>
#include <l4/lib/string.h>
#include <l4/generic/scheduler.h>
#include <l4/generic/space.h>
#include <l4/generic/bootmem.h>
#include <l4/generic/resource.h>
#include <l4/api/errno.h>
#include INC_SUBARCH(mm.h)
#include INC_SUBARCH(mmu_ops.h)
#include INC_GLUE(memory.h)
#include INC_PLAT(printascii.h)
#include INC_GLUE(memlayout.h)
#include INC_ARCH(linker.h)
#include INC_ARCH(asm.h)
#include INC_API(kip.h)
/*
* These are indices into arrays with pgd_t or pmd_t sized elements,
* therefore the index must be divided by appropriate element size
*/
#define PGD_INDEX(x) (((((unsigned long)(x)) >> 18) & 0x3FFC) / sizeof(pgd_t))
/* Strip out the page offset in this megabyte from a total of 256 pages. */
#define PMD_INDEX(x) (((((unsigned long)(x)) >> 10) & 0x3FC) / sizeof (pmd_t))
/*
* Removes initial mappings needed for transition to virtual memory.
* Used one-time only.
*/
void remove_section_mapping(unsigned long vaddr)
{
pgd_table_t *pgd = &init_pgd;;
pgd_t pgd_i = PGD_INDEX(vaddr);
if (!((pgd->entry[pgd_i] & PGD_TYPE_MASK)
& PGD_TYPE_SECTION))
while(1);
pgd->entry[pgd_i] = 0;
pgd->entry[pgd_i] |= PGD_TYPE_FAULT;
arm_invalidate_tlb();
}
/*
* Maps given section-aligned @paddr to @vaddr using enough number
* of section-units to fulfill @size in sections. Note this overwrites
* a mapping if same virtual address was already mapped.
*/
void __add_section_mapping_init(unsigned int paddr,
unsigned int vaddr,
unsigned int size,
unsigned int flags)
{
pte_t *ppte;
unsigned int l1_ptab;
unsigned int l1_offset;
/* 1st level page table address */
l1_ptab = virt_to_phys(&init_pgd);
/* Get the section offset for this vaddr */
l1_offset = (vaddr >> 18) & 0x3FFC;
/* The beginning entry for mapping */
ppte = (unsigned int *)(l1_ptab + l1_offset);
for(int i = 0; i < size; i++) {
*ppte = 0; /* Clear out old value */
*ppte |= paddr; /* Assign physical address */
*ppte |= PGD_TYPE_SECTION; /* Assign translation type */
/* Domain is 0, therefore no writes. */
/* Only kernel access allowed */
*ppte |= (SVC_RW_USR_NONE << SECTION_AP0);
/* Cacheability/Bufferability flags */
*ppte |= flags;
ppte++; /* Next section entry */
paddr += ARM_SECTION_SIZE; /* Next physical section */
}
return;
}
void add_section_mapping_init(unsigned int paddr, unsigned int vaddr,
unsigned int size, unsigned int flags)
{
unsigned int psection;
unsigned int vsection;
/* Align each address to the pages they reside in */
psection = paddr & ~ARM_SECTION_MASK;
vsection = vaddr & ~ARM_SECTION_MASK;
if(size == 0)
return;
__add_section_mapping_init(psection, vsection, size, flags);
return;
}
/* TODO: Make sure to flush tlb entry and caches */
void __add_mapping(unsigned int paddr, unsigned int vaddr,
unsigned int flags, pmd_table_t *pmd)
{
unsigned int pmd_i = PMD_INDEX(vaddr);
pmd->entry[pmd_i] = paddr;
pmd->entry[pmd_i] |= PMD_TYPE_SMALL; /* Small page type */
pmd->entry[pmd_i] |= flags;
/* TODO: Is both required? Investigate */
/* TEST:
* I think cleaning or invalidating the cache is not required,
* because the entries in the cache aren't for the new mapping anyway.
* It's required if a mapping is removed, but not when newly added.
*/
arm_clean_invalidate_cache();
/* TEST: tlb must be flushed because a new mapping is present in page
* tables, and tlb is inconsistent with the page tables */
arm_invalidate_tlb();
}
/* Return whether a pmd associated with @vaddr is mapped on a pgd or not. */
pmd_table_t *pmd_exists(pgd_table_t *pgd, unsigned long vaddr)
{
unsigned int pgd_i = PGD_INDEX(vaddr);
/* Return true if non-zero pgd entry */
switch (pgd->entry[pgd_i] & PGD_TYPE_MASK) {
case PGD_TYPE_COARSE:
return (pmd_table_t *)
phys_to_virt((pgd->entry[pgd_i] &
PGD_COARSE_ALIGN_MASK));
break;
case PGD_TYPE_FAULT:
return 0;
break;
case PGD_TYPE_SECTION:
dprintk("Warning, a section is already mapped "
"where a coarse page mapping is attempted:",
(u32)(pgd->entry[pgd_i]
& PGD_SECTION_ALIGN_MASK));
BUG();
break;
case PGD_TYPE_FINE:
dprintk("Warning, a fine page table is already mapped "
"where a coarse page mapping is attempted:",
(u32)(pgd->entry[pgd_i]
& PGD_FINE_ALIGN_MASK));
printk("Fine tables are unsupported. ");
printk("What is this doing here?");
BUG();
break;
default:
dprintk("Unrecognised pmd type @ pgd index:", pgd_i);
BUG();
break;
}
return 0;
}
/* Convert a virtual address to a pte if it exists in the page tables. */
pte_t virt_to_pte_from_pgd(unsigned long virtual, pgd_table_t *pgd)
{
pmd_table_t *pmd = pmd_exists(pgd, virtual);
if (pmd)
return (pte_t)pmd->entry[PMD_INDEX(virtual)];
else
return (pte_t)0;
}
/* Convert a virtual address to a pte if it exists in the page tables. */
pte_t virt_to_pte(unsigned long virtual)
{
return virt_to_pte_from_pgd(virtual, TASK_PGD(current));
}
unsigned long virt_to_phys_by_pgd(unsigned long vaddr, pgd_table_t *pgd)
{
pte_t pte = virt_to_pte_from_pgd(vaddr, pgd);
return pte & ~PAGE_MASK;
}
unsigned long virt_to_phys_by_task(unsigned long vaddr, struct ktcb *task)
{
return virt_to_phys_by_pgd(vaddr, TASK_PGD(task));
}
void attach_pmd(pgd_table_t *pgd, pmd_table_t *pmd, unsigned int vaddr)
{
u32 pgd_i = PGD_INDEX(vaddr);
u32 pmd_phys = virt_to_phys(pmd);
/* Domain is 0, therefore no writes. */
pgd->entry[pgd_i] = (pgd_t)pmd_phys;
pgd->entry[pgd_i] |= PGD_TYPE_COARSE;
}
/*
* Same as normal mapping but with some boot tweaks.
*/
void add_boot_mapping(unsigned int paddr, unsigned int vaddr,
unsigned int size, unsigned int flags)
{
pmd_table_t *pmd;
pgd_table_t *pgd = &init_pgd;
unsigned int numpages = (size >> PAGE_BITS);
if (size < PAGE_SIZE) {
printascii("Error: Mapping size must be in bytes not pages.\n");
while(1);
}
if (size & PAGE_MASK)
numpages++;
/* Convert generic map flags to pagetable-specific */
BUG_ON(!(flags = space_flags_to_ptflags(flags)));
/* Map all consecutive pages that cover given size */
for (int i = 0; i < numpages; i++) {
/* Check if another mapping already has a pmd attached. */
pmd = pmd_exists(pgd, vaddr);
if (!pmd) {
/*
* If this is the first vaddr in
* this pmd, allocate new pmd
*/
pmd = alloc_boot_pmd();
/* Attach pmd to its entry in pgd */
attach_pmd(pgd, pmd, vaddr);
}
/* Attach paddr to this pmd */
__add_mapping(page_align(paddr),
page_align(vaddr), flags, pmd);
/* Go to the next page to be mapped */
paddr += PAGE_SIZE;
vaddr += PAGE_SIZE;
}
}
/*
* Maps @paddr to @vaddr, covering @size bytes also allocates new pmd if
* necessary. This flavor explicitly supplies the pgd to modify. This is useful
* when modifying userspace of processes that are not currently running. (Only
* makes sense for userspace mappings since kernel mappings are common.)
*/
void add_mapping_pgd(unsigned int paddr, unsigned int vaddr,
unsigned int size, unsigned int flags,
pgd_table_t *pgd)
{
pmd_table_t *pmd;
unsigned int numpages = (size >> PAGE_BITS);
if (size < PAGE_SIZE) {
printascii("Error: Mapping size must be in bytes not pages.\n");
while(1);
}
if (size & PAGE_MASK)
numpages++;
/* Convert generic map flags to pagetable-specific */
BUG_ON(!(flags = space_flags_to_ptflags(flags)));
/* Map all consecutive pages that cover given size */
for (int i = 0; i < numpages; i++) {
/* Check if another mapping already has a pmd attached. */
pmd = pmd_exists(pgd, vaddr);
if (!pmd) {
/*
* If this is the first vaddr in
* this pmd, allocate new pmd
*/
pmd = alloc_pmd();
/* Attach pmd to its entry in pgd */
attach_pmd(pgd, pmd, vaddr);
}
/* Attach paddr to this pmd */
__add_mapping(page_align(paddr),
page_align(vaddr), flags, pmd);
/* Go to the next page to be mapped */
paddr += PAGE_SIZE;
vaddr += PAGE_SIZE;
}
}
void add_mapping(unsigned int paddr, unsigned int vaddr,
unsigned int size, unsigned int flags)
{
add_mapping_pgd(paddr, vaddr, size, flags, TASK_PGD(current));
}
/*
* Checks if a virtual address range has same or more permissive
* flags than the given ones, returns 0 if not, and 1 if OK.
*/
int check_mapping_pgd(unsigned long vaddr, unsigned long size,
unsigned int flags, pgd_table_t *pgd)
{
unsigned int npages = __pfn(align_up(size, PAGE_SIZE));
pte_t pte;
/* Convert generic map flags to pagetable-specific */
BUG_ON(!(flags = space_flags_to_ptflags(flags)));
for (int i = 0; i < npages; i++) {
pte = virt_to_pte_from_pgd(vaddr + i * PAGE_SIZE, pgd);
/* Check if pte perms are equal or gt given flags */
if ((pte & PTE_PROT_MASK) >= (flags & PTE_PROT_MASK))
continue;
else
return 0;
}
return 1;
}
int check_mapping(unsigned long vaddr, unsigned long size,
unsigned int flags)
{
return check_mapping_pgd(vaddr, size, flags, TASK_PGD(current));
}
/* FIXME: Empty PMDs should be returned here !!! */
int __remove_mapping(pmd_table_t *pmd, unsigned long vaddr)
{
pmd_t pmd_i = PMD_INDEX(vaddr);
int ret;
switch (pmd->entry[pmd_i] & PMD_TYPE_MASK) {
case PMD_TYPE_FAULT:
ret = -ENOENT;
break;
case PMD_TYPE_LARGE:
pmd->entry[pmd_i] = 0;
pmd->entry[pmd_i] |= PMD_TYPE_FAULT;
ret = 0;
break;
case PMD_TYPE_SMALL:
pmd->entry[pmd_i] = 0;
pmd->entry[pmd_i] |= PMD_TYPE_FAULT;
ret = 0;
break;
default:
printk("Unknown page mapping in pmd. Assuming bug.\n");
BUG();
}
return ret;
}
/*
* Tell if a pgd index is a common kernel index. This is used to distinguish
* common kernel entries in a pgd, when copying page tables.
*/
int is_kern_pgdi(int i)
{
if ((i >= PGD_INDEX(KERNEL_AREA_START) && i < PGD_INDEX(KERNEL_AREA_END)) ||
(i >= PGD_INDEX(IO_AREA_START) && i < PGD_INDEX(IO_AREA_END)) ||
(i == PGD_INDEX(USER_KIP_PAGE)) ||
(i == PGD_INDEX(ARM_HIGH_VECTOR)) ||
(i == PGD_INDEX(ARM_SYSCALL_VECTOR)) ||
(i == PGD_INDEX(USERSPACE_CONSOLE_VIRTUAL)))
return 1;
else
return 0;
}
/*
* Removes all userspace mappings from a pgd. Frees any pmds that it
* detects to be user pmds
*/
int remove_mapping_pgd_all_user(pgd_table_t *pgd)
{
pmd_table_t *pmd;
/* Traverse through all pgd entries */
for (int i = 0; i < PGD_ENTRY_TOTAL; i++) {
/* Detect a pgd entry that is not a kernel entry */
if (!is_kern_pgdi(i)) {
/* Detect a pmd entry */
if (((pgd->entry[i] & PGD_TYPE_MASK)
== PGD_TYPE_COARSE)) {
/* Obtain the user pmd handle */
pmd = (pmd_table_t *)
phys_to_virt((pgd->entry[i] &
PGD_COARSE_ALIGN_MASK));
/* Free it */
free_pmd(pmd);
}
/* Clear the pgd entry */
pgd->entry[i] = PGD_TYPE_FAULT;
}
}
return 0;
}
int remove_mapping_pgd(unsigned long vaddr, pgd_table_t *pgd)
{
pgd_t pgd_i = PGD_INDEX(vaddr);
pmd_table_t *pmd;
pmd_t pmd_i;
int ret;
/*
* Clean the cache to main memory before removing the mapping. Otherwise
* entries in the cache for this mapping will cause tranlation faults
* if they're cleaned to main memory after the mapping is removed.
*/
arm_clean_invalidate_cache();
/* TEST:
* Can't think of a valid reason to flush tlbs here, but keeping it just
* to be safe. REMOVE: Remove it if it's unnecessary.
*/
arm_invalidate_tlb();
/* Return true if non-zero pgd entry */
switch (pgd->entry[pgd_i] & PGD_TYPE_MASK) {
case PGD_TYPE_COARSE:
// printk("Removing coarse mapping @ 0x%x\n", vaddr);
pmd = (pmd_table_t *)
phys_to_virt((pgd->entry[pgd_i]
& PGD_COARSE_ALIGN_MASK));
pmd_i = PMD_INDEX(vaddr);
ret = __remove_mapping(pmd, vaddr);
break;
case PGD_TYPE_FAULT:
ret = -ENOMAP;
break;
case PGD_TYPE_SECTION:
printk("Removing section mapping for 0x%lx",
vaddr);
pgd->entry[pgd_i] = 0;
pgd->entry[pgd_i] |= PGD_TYPE_FAULT;
ret = 0;
break;
case PGD_TYPE_FINE:
printk("Table mapped is a fine page table.\n"
"Fine tables are unsupported. Assuming bug.\n");
BUG();
break;
default:
dprintk("Unrecognised pmd type @ pgd index:", pgd_i);
printk("Assuming bug.\n");
BUG();
break;
}
/* The tlb must be invalidated here because it might have cached the
* old translation for this mapping. */
arm_invalidate_tlb();
return ret;
}
int remove_mapping(unsigned long vaddr)
{
return remove_mapping_pgd(vaddr, TASK_PGD(current));
}
int delete_page_tables(struct address_space *space)
{
remove_mapping_pgd_all_user(space->pgd);
free_pgd(space->pgd);
return 0;
}
/*
* Copies userspace entries of one task to another. In order to do that,
* it allocates new pmds and copies the original values into new ones.
*/
int copy_user_tables(struct address_space *new, struct address_space *orig_space)
{
pgd_table_t *to = new->pgd, *from = orig_space->pgd;
pmd_table_t *pmd, *orig;
/* Allocate and copy all pmds that will be exclusive to new task. */
for (int i = 0; i < PGD_ENTRY_TOTAL; i++) {
/* Detect a pmd entry that is not a kernel pmd? */
if (!is_kern_pgdi(i) &&
((from->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE)) {
/* Allocate new pmd */
if (!(pmd = alloc_pmd()))
goto out_error;
/* Find original pmd */
orig = (pmd_table_t *)
phys_to_virt((from->entry[i] &
PGD_COARSE_ALIGN_MASK));
/* Copy original to new */
memcpy(pmd, orig, sizeof(pmd_table_t));
/* Replace original pmd entry in pgd with new */
to->entry[i] = (pgd_t)virt_to_phys(pmd);
to->entry[i] |= PGD_TYPE_COARSE;
}
}
return 0;
out_error:
/* Find all non-kernel pmds we have just allocated and free them */
for (int i = 0; i < PGD_ENTRY_TOTAL; i++) {
/* Non-kernel pmd that has just been allocated. */
if (!is_kern_pgdi(i) &&
(to->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE) {
/* Obtain the pmd handle */
pmd = (pmd_table_t *)
phys_to_virt((to->entry[i] &
PGD_COARSE_ALIGN_MASK));
/* Free pmd */
free_pmd(pmd);
}
}
return -ENOMEM;
}
int pgd_count_pmds(pgd_table_t *pgd)
{
int npmd = 0;
for (int i = 0; i < PGD_ENTRY_TOTAL; i++)
if ((pgd->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE)
npmd++;
return npmd;
}
/*
* Allocates and copies all levels of page tables from one task to another.
* Useful when forking.
*
* The copied page tables end up having shared pmds for kernel entries
* and private copies of same pmds for user entries.
*/
pgd_table_t *copy_page_tables(pgd_table_t *from)
{
pmd_table_t *pmd, *orig;
pgd_table_t *pgd;
/* Allocate and copy pgd. This includes all kernel entries */
if (!(pgd = alloc_pgd()))
return PTR_ERR(-ENOMEM);
/* First copy whole pgd entries */
memcpy(pgd, from, sizeof(pgd_table_t));
/* Allocate and copy all pmds that will be exclusive to new task. */
for (int i = 0; i < PGD_ENTRY_TOTAL; i++) {
/* Detect a pmd entry that is not a kernel pmd? */
if (!is_kern_pgdi(i) &&
((pgd->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE)) {
/* Allocate new pmd */
if (!(pmd = alloc_pmd()))
goto out_error;
/* Find original pmd */
orig = (pmd_table_t *)
phys_to_virt((pgd->entry[i] &
PGD_COARSE_ALIGN_MASK));
/* Copy original to new */
memcpy(pmd, orig, sizeof(pmd_table_t));
/* Replace original pmd entry in pgd with new */
pgd->entry[i] = (pgd_t)virt_to_phys(pmd);
pgd->entry[i] |= PGD_TYPE_COARSE;
}
}
return pgd;
out_error:
/* Find all allocated non-kernel pmds and free them */
for (int i = 0; i < PGD_ENTRY_TOTAL; i++) {
/* Non-kernel pmd that has just been allocated. */
if (!is_kern_pgdi(i) &&
(pgd->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE) {
/* Obtain the pmd handle */
pmd = (pmd_table_t *)
phys_to_virt((pgd->entry[i] &
PGD_COARSE_ALIGN_MASK));
/* Free pmd */
free_pmd(pmd);
}
}
/* Free the pgd */
free_pgd(pgd);
return PTR_ERR(-ENOMEM);
}
extern pmd_table_t *pmd_array;
/*
* Jumps from boot pmd/pgd page tables to tables allocated from the cache.
*/
pgd_table_t *realloc_page_tables(void)
{
pgd_table_t *pgd_new = alloc_pgd();
pgd_table_t *pgd_old = &init_pgd;
pmd_table_t *orig, *pmd;
/* Copy whole pgd entries */
memcpy(pgd_new, pgd_old, sizeof(pgd_table_t));
/* Allocate and copy all pmds */
for (int i = 0; i < PGD_ENTRY_TOTAL; i++) {
/* Detect a pmd entry */
if ((pgd_old->entry[i] & PGD_TYPE_MASK) == PGD_TYPE_COARSE) {
/* Allocate new pmd */
if (!(pmd = alloc_pmd())) {
printk("FATAL: PMD allocation "
"failed during system initialization\n");
BUG();
}
/* Find original pmd */
orig = (pmd_table_t *)
phys_to_virt((pgd_old->entry[i] &
PGD_COARSE_ALIGN_MASK));
/* Copy original to new */
memcpy(pmd, orig, sizeof(pmd_table_t));
/* Replace original pmd entry in pgd with new */
pgd_new->entry[i] = (pgd_t)virt_to_phys(pmd);
pgd_new->entry[i] |= PGD_TYPE_COARSE;
}
}
/* Switch the virtual memory system into new area */
arm_clean_invalidate_cache();
arm_drain_writebuffer();
arm_invalidate_tlb();
arm_set_ttb(virt_to_phys(pgd_new));
arm_invalidate_tlb();
printk("%s: Initial page tables moved from 0x%x to 0x%x physical\n",
__KERNELNAME__, virt_to_phys(pgd_old),
virt_to_phys(pgd_new));
return pgd_new;
}
/*
* Useful for upgrading to page-grained control over a section mapping:
* Remaps a section mapping in pages. It allocates a pmd, (at all times because
* there can't really be an already existing pmd for a section mapping) fills
* in the page information, and origaces the direct section physical translation
* with the address of the pmd. Flushes the caches/tlbs.
*/
void remap_as_pages(void *vstart, void *vend)
{
unsigned long pstart = virt_to_phys(vstart);
unsigned long pend = virt_to_phys(vend);
unsigned long paddr = pstart;
pgd_t pgd_i = PGD_INDEX(vstart);
pmd_t pmd_i = PMD_INDEX(vstart);
pgd_table_t *pgd = &init_pgd;
pmd_table_t *pmd = alloc_boot_pmd();
u32 pmd_phys = virt_to_phys(pmd);
int numpages = __pfn(pend - pstart);
/* Fill in the pmd first */
for (int n = 0; n < numpages; n++) {
pmd->entry[pmd_i + n] = paddr;
pmd->entry[pmd_i + n] |= PMD_TYPE_SMALL; /* Small page type */
pmd->entry[pmd_i + n] |= space_flags_to_ptflags(MAP_SVC_DEFAULT_FLAGS);
paddr += PAGE_SIZE;
}
/* Fill in the type to produce a complete pmd translator information */
pmd_phys |= PGD_TYPE_COARSE;
/* Make sure memory is coherent first. */
arm_clean_invalidate_cache();
arm_invalidate_tlb();
/* Replace the direct section physical address with pmd's address */
pgd->entry[pgd_i] = (pgd_t)pmd_phys;
printk("%s: Kernel area 0x%lx - 0x%lx remapped as %d pages\n", __KERNELNAME__,
(unsigned long)vstart, (unsigned long)vend, numpages);
}
void copy_pgds_by_vrange(pgd_table_t *to, pgd_table_t *from,
unsigned long start, unsigned long end)
{
unsigned long start_i = PGD_INDEX(start);
unsigned long end_i = PGD_INDEX(end);
unsigned long irange = (end_i != 0) ? (end_i - start_i)
: (PGD_ENTRY_TOTAL - start_i);
memcpy(&to->entry[start_i], &from->entry[start_i],
irange * sizeof(pgd_t));
}
/* Scheduler uses this to switch context */
void arch_hardware_flush(pgd_table_t *pgd)
{
arm_clean_invalidate_cache();
arm_invalidate_tlb();
arm_set_ttb(virt_to_phys(pgd));
arm_invalidate_tlb();
}

View File

@@ -1,90 +0,0 @@
/*
* ARM v5 Binary semaphore (mutex) implementation.
*
* Copyright (C) 2007 Bahadir Balban
*
*/
#include INC_ARCH(asm.h)
/* 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.
*/
#define MUTEX_UNLOCKED 0
#define MUTEX_LOCKED 1
BEGIN_PROC(__spin_lock)
mov r1, #1
__spin:
swp r2, r1, [r0]
cmp r2, #0
bne __spin
mov pc, lr
END_PROC(__spin_lock)
BEGIN_PROC(__spin_unlock)
mov r1, #0
swp r2, r1, [r0]
cmp r2, #1 @ Debug check.
1:
bne 1b
mov pc, lr
END_PROC(__spin_unlock)
/*
* @r0: Address of mutex location.
*/
BEGIN_PROC(__mutex_lock)
mov r1, #1
swp r2, r1, [r0]
cmp r2, #0
movne r0, #0
moveq r0, #1
mov pc, lr
END_PROC(__mutex_lock)
/*
* @r0: Address of mutex location.
*/
BEGIN_PROC(__mutex_unlock)
mov r1, #0
swp r2, r1, [r0]
cmp r2, #1
1: @ Debug check.
bne 1b
mov pc, lr
END_PROC(__mutex_unlock)
/*
* @r0: Address of mutex location.
*/
BEGIN_PROC(__mutex_inc)
swp r2, r1, [r0]
mov r1, #1
swp r2, r1, [r0]
cmp r2, #0
movne r0, #0
moveq r0, #1
mov pc, lr
END_PROC(__mutex_inc)
/*
* @r0: Address of mutex location.
*/
BEGIN_PROC(__mutex_dec)
mov r1, #0
swp r2, r1, [r0]
cmp r2, #1
1: @ Debug check.
bne 1b
mov pc, lr
END_PROC(__mutex_dec)

View File

@@ -1,115 +0,0 @@
/*
* SP804 Primecell Timer driver
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/drivers/timer/sp804/sp804_timer.h>
#include INC_PLAT(irq.h)
/* FIXME: Fix the shameful uart driver and change to single definition of this! */
#if defined(read)
#undef read
#endif
#if defined(write)
#undef write
#endif
#define read(a) *((volatile unsigned int *)(a))
#define write(v, a) (*((volatile unsigned int *)(a)) = v)
#define setbit(bit, a) write(read(a) | bit, a)
#define clrbit(bit, a) write(read(a) & ~bit, a)
#define devio(base, reg, bit, setclr) ((setclr) ? setbit(bit, base + reg) \
: clrbit(bit, base + reg))
void sp804_irq_handler(unsigned int timer_base)
{
/*
* Timer enabled as Periodic/Wrapper only needs irq clearing
* as it automatically reloads and wraps
*/
write(1, (timer_base + SP804_TIMERINTCLR));
}
static inline void sp804_control(unsigned int timer_base, int bit, int setclr)
{
unsigned long addr = (timer_base + SP804_TIMERCONTROL);
setclr ? setbit(bit, addr) : clrbit(bit, addr);
}
/*
* Sets timer's run mode:
* @periodic: periodic mode = 1, free-running = 0.
*/
#define SP804_PEREN (1 << 6)
static inline void sp804_set_runmode(unsigned int timer_base, int periodic)
{
sp804_control(timer_base, SP804_PEREN, periodic);
}
/*
* Sets timer's wrapping mode:
* @oneshot: oneshot = 1, wrapping = 0.
*/
#define SP804_ONESHOT (1 << 0)
static inline void sp804_set_wrapmode(unsigned int timer_base, int oneshot)
{
sp804_control(timer_base, SP804_ONESHOT, oneshot);
}
/*
* Sets the operational width of timers.
* In 16bit mode, top halfword is ignored.
* @width: 32bit mode = 1; 16bit mode = 0
*/
#define SP804_32BIT (1 << 1)
static inline void sp804_set_widthmode(unsigned int timer_base, int width)
{
sp804_control(timer_base, SP804_32BIT, width);
}
/*
* Enable/disable timer:
* @enable: enable = 1, disable = 0;
*/
#define SP804_ENABLE (1 << 7)
void sp804_enable(unsigned int timer_base, int enable)
{
sp804_control(timer_base, SP804_ENABLE, enable);
}
/*
* Enable/disable local irq register:
* @enable: enable = 1, disable = 0
*/
#define SP804_IRQEN (1 << 5)
void sp804_set_irq(unsigned int timer_base, int enable)
{
sp804_control(timer_base, SP804_IRQEN, enable);
}
/* Loads timer with value in val */
static inline void sp804_load_value(unsigned int timer_base, u32 val)
{
write(val, (timer_base + SP804_TIMERLOAD));
}
/* Returns current timer value */
static inline u32 sp804_read_value(unsigned int timer_base)
{
return read(timer_base + SP804_TIMERVALUE);
}
/* TODO: Define macro values for duration */
void sp804_init(unsigned int timer_base, int run_mode, int wrap_mode, \
int width, int irq_enable)
{
/* 1 tick per usec */
const int duration = 250;
sp804_set_runmode(timer_base, run_mode); /* Periodic */
sp804_set_wrapmode(timer_base, wrap_mode); /* Wrapping */
sp804_set_widthmode(timer_base, width); /* 32 bit */
sp804_set_irq(timer_base, irq_enable); /* Enable */
sp804_load_value(timer_base, duration);
}

View File

@@ -1,264 +0,0 @@
/*
* PL011 Primecell UART driver
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/drivers/uart/pl011/pl011_uart.h>
#include <l4/lib/bit.h>
#include INC_PLAT(platform.h)
struct pl011_uart uart;
/* UART-specific internal error codes.
* TODO: Replace them when generic error codes are in place */
#define PL011_ERROR 1
#define PL011_EAGAIN 2
/* 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)
int pl011_tx_char(unsigned int uart_base, char c)
{
unsigned int val = 0;
read(val, (uart_base + PL011_UARTFR));
if(val & PL011_TXFF) {
/* TX FIFO Full */
return -PL011_EAGAIN;
}
write(c, (uart_base + PL011_UARTDR));
return 0;
}
int pl011_rx_char(unsigned int uart_base, char * c)
{
unsigned int data;
unsigned int val = 0;
read(val, (uart_base + PL011_UARTFR));
if(val & PL011_RXFE) {
/* RX FIFO Empty */
return -PL011_EAGAIN;
}
read(data, (uart_base + PL011_UARTDR));
*c = (char) data;
if((data >> 8) & 0xF) {
/* There were errors, signal error */
return -1;
}
return 0;
}
/*
* 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 int uart_base, unsigned int baud, \
unsigned int clkrate)
{
const unsigned int uartclk = 24000000; /* 24Mhz clock fixed on pb926 */
unsigned int val = 0;
unsigned int 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 / (16 * 38400) */
ipart = 39;
write(ipart, (uart_base + PL011_UARTIBRD));
write(fpart, (uart_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
*/
read(val, (uart_base + PL011_UARTLCR_H));
write(val, (uart_base + PL011_UARTLCR_H));
return;
}
/* Masks the irqs given in the flags bitvector. */
void pl011_set_irq_mask(unsigned int uart_base, unsigned int flags)
{
unsigned int val = 0;
if(flags > 0x3FF) {
/* Invalid irqmask bitvector */
return;
}
read(val, (uart_base + PL011_UARTIMSC));
val |= flags;
write(val, (uart_base + PL011_UARTIMSC));
return;
}
/* Clears the irqs given in flags from masking */
void pl011_clr_irq_mask(unsigned int uart_base, unsigned int flags)
{
unsigned int val = 0;
if(flags > 0x3FF) {
/* Invalid irqmask bitvector */
return;
}
read(val, (uart_base + PL011_UARTIMSC));
val &= ~flags;
write(val, (uart_base + PL011_UARTIMSC));
return;
}
/*
* Produces 1 character from data register and appends it into
* rx buffer keeps record of timeout errors if one occurs.
*/
void pl011_rx_irq_handler(struct pl011_uart * uart, unsigned int flags)
{
/*
* Currently we do nothing for uart irqs, because there's no external
* client to send/receive data (e.g. userspace processes kernel threads).
*/
return;
}
/* Consumes 1 character from tx buffer and attempts to transmit it */
void pl011_tx_irq_handler(struct pl011_uart * uart, unsigned int flags)
{
/*
* Currently we do nothing for uart irqs, because there's no external
* client to send/receive data (e.g. userspace processes kernel threads).
*/
return;
}
/* Updates error counts and exits. Does nothing to recover errors */
void pl011_error_irq_handler(struct pl011_uart * uart, unsigned int flags)
{
if(flags & PL011_FEIRQ) {
uart->frame_errors++;
}
if(flags & PL011_PEIRQ) {
uart->parity_errors++;
}
if(flags & PL011_BEIRQ) {
uart->break_errors++;
}
if(flags & PL011_OEIRQ) {
uart->overrun_errors++;
}
return;
}
void (* pl011_handlers[]) (struct pl011_uart *, unsigned int) = {
0, /* Modem RI */
0, /* Modem CTS */
0, /* Modem DCD */
0, /* Modem DSR */
&pl011_rx_irq_handler, /* Rx */
&pl011_tx_irq_handler, /* Tx */
&pl011_rx_irq_handler, /* Rx timeout */
&pl011_error_irq_handler, /* Framing error */
&pl011_error_irq_handler, /* Parity error */
&pl011_error_irq_handler, /* Break error */
&pl011_error_irq_handler /* Overrun error */
};
/* UART main entry for irq handling. It redirects actual
* handling to handlers relevant to the irq that has occured.
*/
void pl011_irq_handler(struct pl011_uart * uart)
{
unsigned int val;
int handler_index;
void (* handler)(struct pl011_uart *, unsigned int);
val = pl011_read_irqstat(uart->base);
handler_index = 32 - __clz(val);
if(!handler_index) { /* No irq */
return;
}
/* Jump to right handler */
handler = (void (*) (struct pl011_uart *, unsigned int))
pl011_handlers[handler_index];
/* If a handler is available, call it */
if(handler)
(*handler)(uart, val);
return;
}
void pl011_initialise_driver(void)
{
pl011_initialise_device(&uart);
}
/* Initialises the uart class data structures, and the device.
* Terminal-like operation is assumed for default settings.
*/
int pl011_initialise_device(struct pl011_uart * uart)
{
uart->frame_errors = 0;
uart->parity_errors = 0;
uart->break_errors = 0;
uart->overrun_errors = 0;
/* 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);
/* Install the irq handler */
/* TODO: INSTALL IT HERE */
/* Enable all irqs */
pl011_clr_irq_mask(uart->base, 0x3FF);
/* Enable rx, tx, and uart chip */
pl011_tx_enable(uart->base);
pl011_rx_enable(uart->base);
pl011_uart_enable(uart->base);
return 0;
}

View File

@@ -1,121 +0,0 @@
/*
* Basic UART printing.
*/
#include INC_ARCH(asm.h)
#include INC_GLUE(memlayout.h)
#include INC_PLAT(offsets.h)
#include INC_SUBARCH(mm.h)
#define UART_DATA_OFFSET 0x0
#define UART0_PHYS_BASE PB926_UART0_BASE
#define UART0_PHYS_BYTE1 (UART0_PHYS_BASE & 0xFF000000)
#define UART0_PHYS_BYTE2 (UART0_PHYS_BASE & 0x00FF0000)
#define UART0_PHYS_BYTE3_4 (UART0_PHYS_BASE & 0x0000FFFF)
#define UART0_VIRT_BASE PLATFORM_CONSOLE_VIRTUAL
#define UART0_VIRT_BYTE1 (UART0_VIRT_BASE & 0xFF000000)
#define UART0_VIRT_BYTE2 (UART0_VIRT_BASE & 0x00FF0000)
#define UART0_VIRT_BYTE3_4 (UART0_VIRT_BASE & 0x0000FFFF)
.macro uart_address rx
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled?
moveq \rx, #UART0_PHYS_BYTE1
orreq \rx, #UART0_PHYS_BYTE2
orreq \rx, #UART0_PHYS_BYTE3_4
movne \rx, #UART0_VIRT_BYTE1
orrne \rx, #UART0_VIRT_BYTE2
orrne \rx, #UART0_VIRT_BYTE3_4
.endm
.macro uart_send, ry, rx
strb \ry, [\rx, #UART_DATA_OFFSET]
.endm
.macro uart_wait, ry, rx
501:
ldr \ry, [\rx, #0x18]
tst \ry, #1 << 5
bne 501b
.endm
.macro uart_busy, ry, rx
501:
ldr \ry, [\rx, #0x18]
tst \ry, #1 << 3
bne 501b
.endm
.text
/*
* Useful debugging routines
*/
BEGIN_PROC(printhex8)
mov r1, #8
b printhex
BEGIN_PROC(printhex4)
mov r1, #4
b printhex
BEGIN_PROC(printhex2)
mov r1, #2
printhex: adr r2, hexbuf
@printhex: ldr r2, =hexbuf
add r3, r2, r1
mov r1, #0
strb r1, [r3]
1: and r1, r0, #15
mov r0, r0, lsr #4
cmp r1, #10
addlt r1, r1, #'0'
addge r1, r1, #'a' - 10
strb r1, [r3, #-1]!
teq r3, r2
bne 1b
mov r0, r2
b printascii
.ltorg
.align
@ vmem-linked image has strings in vmem addresses. This replaces
@ the reference with corresponding physical address. Note this
@ won't work if memory offsets aren't clear cut values for
@ orr'ing and bic'ing. rm = mmu bits rs = string address.
.macro get_straddr rs, rm
mrc p15, 0, \rm, c1, c0 @ Get MMU bits.
tst \rm, #1 @ MMU enabled?
@subeq \rs, \rs, #KERNEL_AREA_START
biceq \rs, \rs, #KERNEL_AREA_START @ Clear Virtual mem offset.
@orreq \rs, \rs, #PHYS_ADDR_BASE @ Add Phy mem offset.
.endm
BEGIN_PROC(printascii)
get_straddr r0, r1
uart_address r3
b 2f
1: uart_wait r2, r3
uart_send r1, r3
uart_busy r2, r3
teq r1, #'\n'
moveq r1, #'\r'
beq 1b
2: teq r0, #0
ldrneb r1, [r0], #1
teqne r1, #0
bne 1b
mov pc, lr
END_PROC(printascii)
BEGIN_PROC(printch)
uart_address r3
mov r1, r0
mov r0, #0
b 1b
hexbuf: .space 16

View File

@@ -1,34 +0,0 @@
/*
* Ties up platform timer with generic timer api
*
* Copyright (C) 2007 Bahadir Balban
*
*/
#include <l4/generic/irq.h>
#include <l4/generic/platform.h>
#include INC_PLAT(platform.h)
#include <l4/drivers/timer/sp804/sp804_timer.h>
#include <l4/drivers/misc/sp810/sp810_sysctrl.h>
/* Microkernel is using TIMER0, so we will initialize only this one */
void timer_init(void)
{
/* Set frequency of timer to 1MHz */
sp810_set_timclk(PLATFORM_TIMER0, 1);
/* Initialise timer */
sp804_init(PLATFORM_TIMER0_VIRTUAL, SP804_TIMER_RUNMODE_PERIODIC, \
SP804_TIMER_WRAPMODE_WRAPPING, SP804_TIMER_WIDTH32BIT, \
SP804_TIMER_IRQENABLE);
}
/* Microkernel is using TIMER0, so we will initialize only this one */
void timer_start(void)
{
/* Enable irq line for TIMER0 */
irq_enable(IRQ_TIMER0);
/* Enable timer */
sp804_enable(PLATFORM_TIMER0_VIRTUAL, 1);
}

View File

@@ -1,29 +0,0 @@
/*
* Ties up platform's uart driver functions with generic API
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/generic/platform.h>
#include INC_PLAT(platform.h)
#include <l4/drivers/uart/pl011/pl011_uart.h>
extern struct pl011_uart uart;
void uart_init()
{
/* We are using UART0 for kernel */
uart.base = PLATFORM_CONSOLE_VIRTUAL;
pl011_initialise_device(&uart);
}
/* Generic uart function that lib/putchar.c expects to see implemented */
void uart_putc(char c)
{
int res;
/* Platform specific uart implementation */
do {
res = pl011_tx_char(uart.base, c);
} while (res < 0);
}