mirror of
https://github.com/drasko/codezero.git
synced 2026-01-11 18:33:16 +01:00
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:
@@ -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')
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
@@ -1,7 +0,0 @@
|
||||
#ifndef __LINKER_H__
|
||||
#define __LINKER_H__
|
||||
|
||||
extern char vma_start[];
|
||||
extern char __end[];
|
||||
|
||||
#endif /* __LINKER_H__ */
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef __CAPABILITY_H__
|
||||
#define __CAPABILITY_H__
|
||||
|
||||
int caps_read_all();
|
||||
|
||||
#endif /* __CAPABILITY_H__ */
|
||||
@@ -1,7 +0,0 @@
|
||||
#ifndef __TESTS_H__
|
||||
#define __TESTS_H__
|
||||
|
||||
|
||||
int capability_test(void);
|
||||
|
||||
#endif /* __TESTS_H__ */
|
||||
@@ -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__ */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
arch-arm
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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));
|
||||
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__*/
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user