Initial commit

This commit is contained in:
Bahadir Balban
2008-01-13 13:53:52 +00:00
commit e2b791a3d8
789 changed files with 95825 additions and 0 deletions

213
tasks/.config Normal file
View File

@@ -0,0 +1,213 @@
#
# Automatically generated make config: don't edit
# Fri Jan 11 15:12:13 2008
#
# TARGET_alpha is not set
TARGET_arm=y
# TARGET_avr32 is not set
# TARGET_bfin is not set
# TARGET_cris is not set
# TARGET_e1 is not set
# TARGET_frv is not set
# TARGET_h8300 is not set
# TARGET_hppa is not set
# TARGET_i386 is not set
# TARGET_i960 is not set
# TARGET_ia64 is not set
# TARGET_m68k is not set
# TARGET_microblaze is not set
# TARGET_mips is not set
# TARGET_nios is not set
# TARGET_nios2 is not set
# TARGET_powerpc is not set
# TARGET_sh is not set
# TARGET_sh64 is not set
# TARGET_sparc is not set
# TARGET_v850 is not set
# TARGET_vax is not set
# TARGET_x86_64 is not set
#
# Target Architecture Features and Options
#
TARGET_ARCH="arm"
FORCE_OPTIONS_FOR_ARCH=y
# CONFIG_ARM_OABI is not set
CONFIG_ARM_EABI=y
CONFIG_GENERIC_ARM=y
# CONFIG_ARM610 is not set
# CONFIG_ARM710 is not set
# CONFIG_ARM7TDMI is not set
# CONFIG_ARM720T is not set
# CONFIG_ARM920T is not set
# CONFIG_ARM922T is not set
# CONFIG_ARM926T is not set
# CONFIG_ARM10T is not set
# CONFIG_ARM1136JF_S is not set
# CONFIG_ARM1176JZ_S is not set
# CONFIG_ARM1176JZF_S is not set
# CONFIG_ARM_SA110 is not set
# CONFIG_ARM_SA1100 is not set
# CONFIG_ARM_XSCALE is not set
# CONFIG_ARM_IWMMXT is not set
TARGET_SUBARCH=""
#
# Using ELF file format
#
ARCH_ANY_ENDIAN=y
ARCH_LITTLE_ENDIAN=y
# ARCH_WANTS_BIG_ENDIAN is not set
ARCH_WANTS_LITTLE_ENDIAN=y
ARCH_HAS_MMU=y
ARCH_USE_MMU=y
UCLIBC_HAS_FLOATS=y
UCLIBC_HAS_FPU=y
DO_C99_MATH=y
KERNEL_HEADERS="/opt/l4-project/tasks/libc/linux-headers/include"
HAVE_DOT_CONFIG=y
#
# General Library Settings
#
# HAVE_NO_PIC is not set
DOPIC=y
# HAVE_NO_SHARED is not set
# ARCH_HAS_NO_LDSO is not set
HAVE_SHARED=y
# FORCE_SHAREABLE_TEXT_SEGMENTS is not set
LDSO_LDD_SUPPORT=y
LDSO_CACHE_SUPPORT=y
# LDSO_PRELOAD_FILE_SUPPORT is not set
LDSO_BASE_FILENAME="ld.so"
# UCLIBC_STATIC_LDCONFIG is not set
# LDSO_RUNPATH is not set
UCLIBC_CTOR_DTOR=y
# HAS_NO_THREADS is not set
UCLIBC_HAS_THREADS=y
# PTHREADS_DEBUG_SUPPORT is not set
LINUXTHREADS_OLD=y
UCLIBC_HAS_LFS=y
# MALLOC is not set
# MALLOC_SIMPLE is not set
MALLOC_STANDARD=y
MALLOC_GLIBC_COMPAT=y
UCLIBC_DYNAMIC_ATEXIT=y
# COMPAT_ATEXIT is not set
# UCLIBC_SUSV3_LEGACY is not set
# UCLIBC_SUSV3_LEGACY_MACROS is not set
UCLIBC_HAS_SHADOW=y
# UCLIBC_HAS_PROGRAM_INVOCATION_NAME is not set
UCLIBC_HAS___PROGNAME=y
# UNIX98PTY_ONLY is not set
ASSUME_DEVPTS=y
UCLIBC_HAS_TM_EXTENSIONS=y
UCLIBC_HAS_TZ_CACHING=y
UCLIBC_HAS_TZ_FILE=y
UCLIBC_HAS_TZ_FILE_READ_MANY=y
UCLIBC_TZ_FILE_PATH="/etc/TZ"
#
# Advanced Library Settings
#
UCLIBC_PWD_BUFFER_SIZE=256
UCLIBC_GRP_BUFFER_SIZE=256
#
# Networking Support
#
# UCLIBC_HAS_IPV6 is not set
UCLIBC_HAS_RPC=y
UCLIBC_HAS_FULL_RPC=y
UCLIBC_HAS_REENTRANT_RPC=y
# UCLIBC_USE_NETLINK is not set
# UCLIBC_HAS_BSD_RES_CLOSE is not set
#
# String and Stdio Support
#
UCLIBC_HAS_STRING_GENERIC_OPT=y
UCLIBC_HAS_STRING_ARCH_OPT=y
UCLIBC_HAS_CTYPE_TABLES=y
UCLIBC_HAS_CTYPE_SIGNED=y
# UCLIBC_HAS_CTYPE_UNSAFE is not set
UCLIBC_HAS_CTYPE_CHECKED=y
# UCLIBC_HAS_CTYPE_ENFORCED is not set
# UCLIBC_HAS_WCHAR is not set
# UCLIBC_HAS_LOCALE is not set
UCLIBC_HAS_HEXADECIMAL_FLOATS=y
UCLIBC_HAS_GLIBC_CUSTOM_PRINTF=y
# USE_OLD_VFPRINTF is not set
UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS=9
UCLIBC_HAS_SCANF_GLIBC_A_FLAG=y
# UCLIBC_HAS_STDIO_BUFSIZ_NONE is not set
# UCLIBC_HAS_STDIO_BUFSIZ_256 is not set
# UCLIBC_HAS_STDIO_BUFSIZ_512 is not set
# UCLIBC_HAS_STDIO_BUFSIZ_1024 is not set
# UCLIBC_HAS_STDIO_BUFSIZ_2048 is not set
UCLIBC_HAS_STDIO_BUFSIZ_4096=y
# UCLIBC_HAS_STDIO_BUFSIZ_8192 is not set
UCLIBC_HAS_STDIO_BUILTIN_BUFFER_NONE=y
# UCLIBC_HAS_STDIO_BUILTIN_BUFFER_4 is not set
# UCLIBC_HAS_STDIO_BUILTIN_BUFFER_8 is not set
# UCLIBC_HAS_STDIO_SHUTDOWN_ON_ABORT is not set
UCLIBC_HAS_STDIO_GETC_MACRO=y
UCLIBC_HAS_STDIO_PUTC_MACRO=y
UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION=y
# UCLIBC_HAS_FOPEN_LARGEFILE_MODE is not set
UCLIBC_HAS_FOPEN_EXCLUSIVE_MODE=y
UCLIBC_HAS_GLIBC_CUSTOM_STREAMS=y
UCLIBC_HAS_PRINTF_M_SPEC=y
UCLIBC_HAS_ERRNO_MESSAGES=y
# UCLIBC_HAS_SYS_ERRLIST is not set
UCLIBC_HAS_SIGNUM_MESSAGES=y
# UCLIBC_HAS_SYS_SIGLIST is not set
UCLIBC_HAS_GNU_GETOPT=y
UCLIBC_HAS_GNU_GETSUBOPT=y
#
# Big and Tall
#
UCLIBC_HAS_REGEX=y
UCLIBC_HAS_REGEX_OLD=y
UCLIBC_HAS_FNMATCH=y
UCLIBC_HAS_FNMATCH_OLD=y
# UCLIBC_HAS_WORDEXP is not set
UCLIBC_HAS_FTW=y
UCLIBC_HAS_GLOB=y
UCLIBC_HAS_GNU_GLOB=y
#
# Library Installation Options
#
SHARED_LIB_LOADER_PREFIX="/lib"
RUNTIME_PREFIX="/"
DEVEL_PREFIX="/usr/"
#
# Security options
#
# UCLIBC_BUILD_PIE is not set
# UCLIBC_HAS_ARC4RANDOM is not set
# HAVE_NO_SSP is not set
# UCLIBC_HAS_SSP is not set
UCLIBC_BUILD_RELRO=y
UCLIBC_BUILD_NOW=y
# UCLIBC_BUILD_NOEXECSTACK is not set
#
# uClibc development/debugging options
#
CROSS_COMPILER_PREFIX="/opt/scratch3/buildroot/build_arm/staging_dir/usr/bin/arm-linux-uclibcgnueabi-"
UCLIBC_EXTRA_CFLAGS=""
# DODEBUG is not set
# DODEBUG_PT is not set
DOSTRIP=y
# DOASSERTS is not set
# SUPPORT_LD_DEBUG is not set
# SUPPORT_LD_DEBUG_EARLY is not set
# UCLIBC_MALLOC_DEBUGGING is not set
WARNINGS="-Wall"
# EXTRA_WARNINGS is not set
# DOMULTI is not set
# UCLIBC_MJN3_ONLY is not set

130
tasks/blkdev0/SConstruct Normal file
View File

@@ -0,0 +1,130 @@
#
# User space application build script
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import sys
import shutil
from string import split
from os.path import join
from glob import glob
task_name = "blkdev0"
# The root directory of the repository where this file resides:
project_root = "../.."
tools_root = join(project_root, "tools")
prev_image = join(project_root, "tasks/mm0/mm0.axf")
libs_path = join(project_root, "libs")
ld_script = "include/linker.lds"
physical_base_ld_script = "include/physical_base.lds"
# libc paths:
libc_variant = "userspace"
libc_libpath = join(libs_path, "c/build/%s" % libc_variant)
libc_incpath = join(libc_libpath, "include")
libc_crt0 = join(libs_path, "c/build/crt/sys-userspace/arch-arm/crt0.o")
libc_name = "c-%s" % libc_variant
# libl4 paths:
libl4_path = "../libl4"
libl4_incpath = join(libl4_path, "include")
#libmem paths:
libmem_path = "../libmem"
libmem_incpath = "../libmem"
# kernel paths:
kernel_incpath = join(project_root, "include")
# Kernel config header.
config_h = join(project_root, "include/l4/config.h")
# If crt0 is in its library path, it becomes hard to link with it.
# For instance the linker script must use an absolute path for it.
def copy_crt0(source, target, env):
os.system("cp " + str(source[0]) + " " + str(target[0]))
def get_physical_base(source, target, env):
os.system(join(tools_root, "pyelf/readelf.py --first-free-page " + \
prev_image +" >> " + physical_base_ld_script))
# The kernel build environment:
env = Environment(CC = 'arm-none-linux-gnueabi-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'],
LINKFLAGS = ['-nostdlib', '-T' + ld_script, "-L" + libc_libpath, "-L" + libl4_path, "-L" + libmem_path],
ASFLAGS = ['-D__ASSEMBLY__'],
PROGSUFFIX = '.axf', # The suffix to use for final executable
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path
LIBS = [libc_name, 'libl4', 'libmm', 'libmc', 'libkm', \
'gcc', libc_name], # libgcc.a - This is required for division routines.
CPPFLAGS = "-D__USERSPACE__",
CPPPATH = ['#include', libl4_incpath, libc_incpath, kernel_incpath, libmem_incpath])
def extract_arch_subarch_plat(config_header):
'''
From the autogenerated kernel config.h, extracts platform, archictecture,
subarchitecture information. This is used to include the relevant headers
from the kernel directories.
'''
arch = None
subarch = None
plat = None
if not os.path.exists(config_header):
print "\n\nconfig.h does not exist. "\
"Please run: `scons configure' first\n\n"
sys.exit()
f = open(config_h, "r")
while True:
line = f.readline()
if line == "":
break
parts = split(line)
if len(parts) > 0:
if parts[0] == "#define":
if parts[1] == "__ARCH__":
arch = parts[2]
elif parts[1] == "__PLATFORM__":
plat = parts[2]
elif parts[1] == "__SUBARCH__":
subarch = parts[2]
f.close()
if arch == None:
print "Error: No config symbol found for architecture"
sys.exit()
if subarch == None:
print "Error: No config symbol found for subarchitecture"
sys.exit()
if plat == None:
print "Error: No config symbol found for platform"
sys.exit()
return arch, subarch, plat
def create_symlinks(arch):
arch_path = "include/arch"
arch_path2 ="src/arch"
if os.path.exists(arch_path):
os.system("rm %s" % (arch_path))
os.system("ln -s %s %s" % ("arch-" + arch, arch_path))
if os.path.exists(arch_path2):
os.system("rm %s" % (arch_path2))
os.system("ln -s %s %s" % ("arch-" + arch, arch_path2))
arch, subarch, plat = extract_arch_subarch_plat(config_h)
create_symlinks(arch) # Creates symlinks to architecture specific directories.
src = [glob("src/*.c"), glob("fsbin/*.S"), glob("*.c"), glob("src/arch/*.c")]
objs = env.Object(src)
physical_base = env.Command(physical_base_ld_script, prev_image, get_physical_base)
crt0_copied = env.Command("crt0.o", libc_crt0, copy_crt0)
task = env.Program(task_name, objs + [crt0_copied])
env.Alias(task_name, task)
env.Depends(task, physical_base)

View File

@@ -0,0 +1,43 @@
#
# Binary to elf build script
# Works by including a binary in an assembler file and linking it.
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import sys
import shutil
from os.path import join
from glob import glob
elfimg_name = "romfs"
# The root directory of the repository where this file resides:
project_root = "../.."
tools_root = join(project_root, "tools")
prev_image = join(project_root, "tasks/test0/test0.axf")
ld_script = "include/linker.lds"
physical_base_ld_script = "include/physical_base.lds"
def get_physical_base(source, target, env):
os.system(join(tools_root, "pyelf/readelf.py --first-free-page " + \
prev_image + " >> " + physical_base_ld_script))
# The kernel build environment:
env = Environment(CC = 'arm-none-linux-gnueabi-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'],
LINKFLAGS = ['-nostdlib', '-T' + ld_script],
ASFLAGS = ['-D__ASSEMBLY__'],
PROGSUFFIX = '.axf', # The suffix to use for final executable
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path
CPPFLAGS = "-D__USERSPACE__",
CPPPATH = ['#include'])
src = [glob("*.S")]
objs = env.Object(src)
physical_base = env.Command(physical_base_ld_script, prev_image, get_physical_base)
task = env.Program(elfimg_name, objs)
env.Alias(elfimg_name, task)
env.Depends(task, physical_base)

View File

@@ -0,0 +1,7 @@
/* This is used to place a binary file into an elf section */
.section .data.fs
.incbin "fsbin/romfs.bin"
.align 4

1
tasks/blkdev0/include/arch Symbolic link
View File

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

View File

@@ -0,0 +1,23 @@
#ifndef __BLKDEV_H__
#define __BLKDEV_H__
struct block_device;
struct block_device_ops {
void (*open)(struct block_device *bdev);
void (*read)(unsigned long offset, int size, void *buf);
void (*write)(unsigned long offset, int size, void *buf);
void (*read_page)(unsigned long pfn, void *buf);
void (*write_page)(unsigned long pfn, void *buf);
};
struct block_device {
char *name;
unsigned long size;
struct block_device_ops ops;
};
void init_blkdev(void);
#endif /* __BLKDEV_H__ */

View File

@@ -0,0 +1,43 @@
/*
* Simple linker script for userspace or svc tasks.
*
* Copyright (C) 2007 Bahadir Balban
*/
/*
* The only catch with this linker script is that everything
* is linked starting at virtual_base, and loaded starting
* at physical_base. virtual_base is the predefined region
* of virtual memory for userland applications. physical_base
* is determined at build-time, it is one of the subsequent pages
* that come after the kernel image's load area.
*/
/* USER_AREA_START, see memlayout.h */
virtual_base = 0x10000000;
__stack = 0x20000000;
INCLUDE "include/physical_base.lds"
/* physical_base = 0x228000; */
offset = virtual_base - physical_base;
ENTRY(_start)
SECTIONS
{
. = virtual_base;
_start_text = .;
.text : AT (ADDR(.text) - offset) { crt0.o(.text) *(.text) }
/* rodata is needed else your strings will link at physical! */
.rodata : AT (ADDR(.rodata) - offset) { *(.rodata) }
.rodata1 : AT (ADDR(.rodata1) - offset) { *(.rodata1) }
.data : AT (ADDR(.data) - offset)
{
. = ALIGN(4K);
_start_ramdisk = .;
*(.data.fs)
_end_ramdisk = .;
*(.data)
}
.bss : AT (ADDR(.bss) - offset) { *(.bss) }
_end = .;
}

View File

@@ -0,0 +1,17 @@
/*
* The next free p_align'ed LMA base address
*
* p_align = 0x8000
*
* Recap from ELF spec: p_align: Loadable process segments must have
* congruent values for p_vaddr and p_offset, modulo the page size.
* This member gives the value to which the segments are aligned in
* memory and in the file. Values 0 and 1 mean that no alignment is
* required. Otherwise, p_align should be a positive, integral power
* of 2, and p_addr should equal p_offset, modulo p_align.
* This essentially means next available address must be aligned at
* p_align, rather than the page_size, which one (well, I) would
* normally expect.
*/
physical_base = 0x3000;

View File

@@ -0,0 +1,6 @@
#ifndef __RAMDISK_H__
#define __RAMDISK_H__
extern struct block_device ramdisk;
#endif

10
tasks/blkdev0/main.c Normal file
View File

@@ -0,0 +1,10 @@
#include <stdio.h>
#include <blkdev.h>
int main(void)
{
init_blkdev();
return 0;
}

1
tasks/blkdev0/src/arch Symbolic link
View File

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

10
tasks/blkdev0/src/init.c Normal file
View File

@@ -0,0 +1,10 @@
#include <blkdev.h>
#include <ramdisk.h>
void init_blkdev(void)
{
ramdisk.ops.open(&ramdisk);
}

View File

@@ -0,0 +1,65 @@
/*
* A basic ramdisk implementation.
*
* Copyright (C) 2007 Bahadir Balban
*
* The ramdisk binary is embedded in the data section of the ramdisk device
* executable. Read/writes simply occur to this area. The disk area could
* have any filesystem layout e.g. romfs, which is irrelevant for this code.
*/
#include <blkdev.h>
#include <ramdisk.h>
#include <l4/macros.h>
#include <l4/config.h>
#include <l4/types.h>
#include <string.h>
#include INC_SUBARCH(mm.h)
#include INC_GLUE(memory.h)
/* Ramdisk section markers for ramdisk inside this executable image */
extern char _start_ramdisk[];
extern char _end_ramdisk[];
static unsigned long ramdisk_base;
void ramdisk_open(struct block_device *ramdisk)
{
ramdisk_base = (unsigned long)_start_ramdisk;
ramdisk->size = (unsigned long)_end_ramdisk -
(unsigned long)_start_ramdisk;
}
void ramdisk_read(unsigned long offset, int size, void *buf)
{
void *src = (void *)(ramdisk_base + offset);
memcpy(buf, src, size);
}
void ramdisk_write(unsigned long offset, int size, void *buf)
{
void *dst = (void *)(ramdisk_base + offset);
memcpy(dst, buf, size);
}
void ramdisk_readpage(unsigned long pfn, void *buf)
{
ramdisk_read(__pfn_to_addr(pfn), PAGE_SIZE, buf);
}
void ramdisk_writepage(unsigned long pfn, void *buf)
{
ramdisk_write(__pfn_to_addr(pfn), PAGE_SIZE, buf);
}
struct block_device ramdisk = {
.name = "ramdisk",
.ops = {
.open = ramdisk_open,
.read = ramdisk_read,
.write = ramdisk_write,
.read_page = ramdisk_readpage,
.write_page = ramdisk_writepage,
},
};

View File

@@ -0,0 +1,28 @@
#!/usr/bin/python
import os
import sys
compiler_prefix = "arm-none-linux-gnueabi-"
objdump = "objdump"
command = "-t"
image_name = "inittask.axf"
linkoutput_file_suffix = "-linkinfo.txt"
linkoutput_file = image_name + linkoutput_file_suffix
def generate_bootdesc():
command = compiler_prefix + objdump + " -t " + image_name + " > " + linkoutput_file
print command
os.system(command)
f = open(linkoutput_file, "r")
while True:
line = f.readline()
if len(line) is 0:
break
if "_start" in line or "_end" in line:
print line
f.close()
if __name__ == "__main__":
generate_bootdesc()

123
tasks/bootdesc/SConstruct Normal file
View File

@@ -0,0 +1,123 @@
#
# Build script to autogenerate a bootdesc image
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import sys
import shutil
from os.path import join
# The root directory of the repository where this file resides:
project_root = "../.."
tools_root = "../../tools"
kernel = join(project_root, "build/start.axf")
mm0 = join(project_root, "tasks/mm0/mm0.axf")
# fs0 = join(project_root, "tasks/fs0/fs0.axf")
test0 = join(project_root, "tasks/test0/test0.axf")
test1 = join(project_root, "tasks/test1/test1.axf")
#blkdev0 = join(project_root, "tasks/fsbin/blkdev0.axf")
images = [kernel, mm0, test0, test1]
autogen_templ = "bootdesc.c.append"
def get_image_name_start_end(image, target):
'''
Using readelf.py utility, extracts name, start, end triplet from an arm-elf image.
'''
rest, name = os.path.split(image)
if name[-4] == ".":
name = name[:-4]
os.system(join(tools_root, "pyelf/readelf.py --lma-start-end " + \
image + " > " + target))
bootdesc_template = \
'''
struct bootdesc bootdesc = {
.desc_size = sizeof(struct bootdesc) + sizeof(struct svc_image) * %s,
.total_images = %s,
.images = {
%s
},
};
'''
images_template = \
''' [%s] = {
.name = "%s",
.phys_start = %s,
.phys_end = %s,
},
'''
images_template_end = \
'''
},
'''
def generate_bootdesc(source, target, env):
'''
Extracts name, start, end information from the kernel and each svc task.
Uses this information to produce bootdesc.c
'''
source.sort()
images = []
images_string = ""
for node in source:
if str(node)[-4:] == ".axf":
rest, imgname = os.path.split(str(node))
images.append((str(node), imgname[:-4]))
elif str(node) [-6:] == ".templ":
# Static template that has type definitions.
#rest, original_template = os.path.split(str(node))
original_template = str(node)
index = 0
for imgpath, imgname in images:
get_image_name_start_end(imgpath, imgname + ".txt")
if imgname != "start":
f = open(imgname + ".txt", "r")
svc_name = f.readline()[:-1]
[start, startval] = str.split(f.readline()[:-1])
[end, endval] = str.split(f.readline()[:-1])
f.close()
images_string += images_template % (str(index), svc_name, \
hex(int(startval, 16)), hex(int(endval, 16)))
index += 1
# Autogenerated template with actual data.
autogen_template = open(autogen_templ, "w+")
autogen_template.write(bootdesc_template % (str(index), str(index), images_string))
autogen_template.close()
os.system("cat " + original_template + " > " + str(target[0]))
os.system("cat " + autogen_templ + " >> " + str(target[0]))
def relocate_bootdesc(source, target, env):
f = open("start.txt", "r")
kernel_name = f.readline()[:-1]
[start, startval] = str.split(f.readline()[:-1])
[end, endval] = str.split(f.readline()[:-1])
os.system("arm-none-linux-gnueabi-objcopy --adjust-section-vma .data=" + \
hex(int(endval,16)) + " " + str(source[0]))
os.system("mv " + str(source[0]) + " " + str(target[0]))
# The kernel build environment:
env = Environment(CC = 'arm-none-linux-gnueabi-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'],
LINKFLAGS = ['-nostdlib','-Tlinker.lds'],
ASFLAGS = ['-D__ASSEMBLY__'],
PROGSUFFIX = '.axf', # The suffix to use for final executable
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path
LIBS = 'gcc', # libgcc.a - This is required for division routines.
CPPPATH = '#include') # `hash' ('#') is a shorthand meaning `relative to
# the root directory'. But this only works for
# well-defined variables, not all paths, and only
# if we use a relative build directory for sources.
bootdesc_src = env.Command("bootdesc.c", ["bootdesc.c.templ"] + images, generate_bootdesc)
objs = env.Object('bootdesc.c')
bootdesc = env.Program('bootdesc_data', objs)
bootdesc_relocated = env.Command("bootdesc.axf", "bootdesc_data.axf", relocate_bootdesc)
env.Depends(bootdesc_relocated, bootdesc)

View File

@@ -0,0 +1,23 @@
struct bootdesc bootdesc = {
.desc_size = sizeof(struct bootdesc) + sizeof(struct svc_image) * 3,
.total_images = 3,
.images = {
[0] = {
.name = "mm0",
.phys_start = 0x208000,
.phys_end = 0x213140,
},
[1] = {
.name = "test0",
.phys_start = 0x218000,
.phys_end = 0x21aedc,
},
[2] = {
.name = "romfs",
.phys_start = 0x220000,
.phys_end = 0x268800,
},
},
};

View File

@@ -0,0 +1,39 @@
/* Supervisor task at load time. */
struct svc_image {
char name[16];
unsigned int phys_start;
unsigned int phys_end;
} __attribute__((__packed__));
/* Supervisor task descriptor at load time */
struct bootdesc {
int desc_size;
int total_images;
struct svc_image images[];
} __attribute__((__packed__));
struct bootdesc bootdesc = {
.desc_size = sizeof(struct bootdesc) + sizeof(struct svc_image) * 3,
.total_images = 3,
.images = {
[0] = {
.name = "inittask",
.phys_start = 0x208000,
.phys_end = 0x213260,
},
[1] = {
.name = "roottask",
.phys_start = 0x218000,
.phys_end = 0x21b344,
},
[2] = {
.name = "testtask",
.phys_start = 0x220000,
.phys_end = 0x223344,
},
},
};

View File

@@ -0,0 +1,16 @@
/* Supervisor task at load time. */
struct svc_image {
char name[16];
unsigned int phys_start;
unsigned int phys_end;
} __attribute__((__packed__));
/* Supervisor task descriptor at load time */
struct bootdesc {
int desc_size;
int total_images;
struct svc_image images[];
} __attribute__((__packed__));

3
tasks/bootdesc/fs0.txt Normal file
View File

@@ -0,0 +1,3 @@
fs0
image_start 0x218000
image_end 0x21B26C

View File

@@ -0,0 +1,3 @@
inittask
image_start 0x208000
image_end 0x213260

View File

@@ -0,0 +1,8 @@
ENTRY(_start)
SECTIONS
{
_start = .;
.data : { *(.data) }
_end = .;
}

3
tasks/bootdesc/mm0.txt Normal file
View File

@@ -0,0 +1,3 @@
mm0
image_start 0x208000
image_end 0x213140

3
tasks/bootdesc/romfs.txt Normal file
View File

@@ -0,0 +1,3 @@
romfs
image_start 0x220000
image_end 0x268800

View File

@@ -0,0 +1,3 @@
roottask
image_start 0x218000
image_end 0x21B344

3
tasks/bootdesc/start.txt Normal file
View File

@@ -0,0 +1,3 @@
start
image_start 0x100000
image_end 0x205800

3
tasks/bootdesc/test0.txt Normal file
View File

@@ -0,0 +1,3 @@
test0
image_start 0x218000
image_end 0x21AEDC

View File

@@ -0,0 +1,3 @@
testtask
image_start 0x220000
image_end 0x223344

View File

66
tasks/fs0/SConstruct Normal file
View File

@@ -0,0 +1,66 @@
#
# User space application build script
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import sys
import shutil
from os.path import join
from glob import glob
task_name = "fs0"
# The root directory of the repository where this file resides:
project_root = "../.."
tools_root = join(project_root, "tools")
prev_image = join(project_root, "tasks/blkdev0/blkdev0.axf")
libs_path = join(project_root, "libs")
ld_script = "include/linker.lds"
physical_base_ld_script = "include/physical_base.lds"
# libc paths:
libc_variant = "userspace"
libc_libpath = join(libs_path, "c/build/%s" % libc_variant)
libc_incpath = join(libc_libpath, "include")
libc_crt0 = join(libs_path, "c/build/crt/sys-userspace/arch-arm/crt0.o")
libc_name = "c-%s" % libc_variant
# libl4 paths:
libl4_path = "../libl4"
libl4_incpath1 = join(libl4_path, "include")
# kernel paths:
kernel_incpath = join(project_root, "include")
# If crt0 is in its library path, it becomes hard to link with it.
# For instance the linker script must use an absolute path for it.
def copy_crt0(source, target, env):
os.system("cp " + str(source[0]) + " " + str(target[0]))
def get_physical_base(source, target, env):
os.system(join(tools_root, "pyelf/readelf.py --first-free-page " + \
prev_image + " >> " + physical_base_ld_script))
# The kernel build environment:
env = Environment(CC = 'arm-none-linux-gnueabi-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'],
LINKFLAGS = ['-nostdlib', '-T' + ld_script, "-L" + libc_libpath, "-L" + libl4_path],
ASFLAGS = ['-D__ASSEMBLY__'],
PROGSUFFIX = '.axf', # The suffix to use for final executable
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path
LIBS = [libc_name, 'gcc', libc_name, \
'libl4'], # libgcc.a - This is required for division routines.
CPPFLAGS = "-D__USERSPACE__",
CPPPATH = ['#include', libl4_incpath1, kernel_incpath, libc_incpath])
src = [glob("src/*.c"), glob("*.c"), glob("src/arch/arm/*.c")]
objs = env.Object(src)
physical_base = env.Command(physical_base_ld_script, prev_image, get_physical_base)
crt0_copied = env.Command("crt0.o", libc_crt0, copy_crt0)
task = env.Program(task_name, objs + [crt0_copied])
env.Alias(task_name, task)
env.Depends(task, physical_base)

8
tasks/fs0/include/bdev.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef __BLOCK_DEV_H__
#define __BLOCK_DEV_H__
void bdev_open(void);
void bdev_readpage(unsigned long offset, void *buf);
void bdev_writepage(unsigned long offset, void *buf);
#endif /* __BLOCK_DEV_H__ */

90
tasks/fs0/include/fs.h Normal file
View File

@@ -0,0 +1,90 @@
/*
* VFS definitions.
*
* Copyright (C) 2007 Bahadir Balban.
*/
#ifndef __FS_H__
#define __FS_H__
#include <l4/lib/list.h>
typedef void (*dentry_op_t)(void);
typedef void (*superblock_op_t)(void);
typedef void (*vnode_op_t)(void);
typedef void (*file_op_t)(void);
struct dentry_ops {
dentry_op_t compare;
};
struct file_ops {
file_op_t open;
file_op_t read;
file_op_t write;
file_op_t close;
file_op_t mmap;
file_op_t seek;
file_op_t flush;
file_op_t fsync;
};
struct vnode_ops {
vnode_op_t create;
vnode_op_t lookup;
vnode_op_t link;
vnode_op_t unlink;
vnode_op_t mkdir;
vnode_op_t rmdir;
vnode_op_t rename;
vnode_op_t getattr;
vnode_op_t setattr;
};
struct superblock_ops {
superblock_op_t read_sb;
superblock_op_t write_sb;
superblock_op_t read_vnode;
superblock_op_t write_vnode;
};
struct dentry;
struct file;
struct filesystem;
struct superblock;
struct vnode;
struct dentry {
int refcnt;
char name[512];
struct dentry *parent; /* Parent dentry */
struct list_head siblings; /* List of dentries with same parent */
struct vnode *vnode; /* The vnode associated with dirent */
struct dentry_ops ops;
};
struct file {
int refcnt;
struct dentry *dentry;
struct file_ops ops;
};
struct vnode {
unsigned long id; /* Filesystem-wide unique vnode id */
int refcnt; /* Reference counter */
struct vnode_ops ops; /* Operations on this vnode */
struct list_head dirents; /* Dirents that refer to this vnode */
struct list_head state_list; /* List for vnode's dirty/clean state */
unsigned long size; /* Total size of vnode in bytes */
};
struct filesystem {
unsigned long magic;
char name[256];
};
struct superblock {
struct filesystem fs;
struct superblock_ops ops;
struct dentry *root_dirent;
};
#endif /* __FS_H__ */

26
tasks/fs0/include/kdata.h Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2007 Bahadir Balban
*/
#ifndef __MM_KDATA_H__
#define __MM_KDATA_H__
#include <l4/macros.h>
#include <l4/config.h>
#include <l4/types.h>
#include <l4/generic/physmem.h>
#include INC_PLAT(offsets.h)
#include INC_GLUE(memory.h)
#include INC_GLUE(memlayout.h)
#include INC_ARCH(bootdesc.h)
#include <vm_area.h>
struct initdata {
struct bootdesc *bootdesc;
struct block_device *bdev;
};
extern struct initdata initdata;
int request_initdata(struct initdata *i);
#endif /* __MM_KDATA_H__ */

View File

@@ -0,0 +1,36 @@
/*
* Simple linker script for userspace or svc tasks.
*
* Copyright (C) 2007 Bahadir Balban
*/
/*
* The only catch with this linker script is that everything
* is linked starting at virtual_base, and loaded starting
* at physical_base. virtual_base is the predefined region
* of virtual memory for userland applications. physical_base
* is determined at build-time, it is one of the subsequent pages
* that come after the kernel image's load area.
*/
/* USER_AREA_START, see memlayout.h */
virtual_base = 0x10000000;
__stack = 0x20000000;
INCLUDE "include/physical_base.lds"
/* physical_base = 0x228000; */
offset = virtual_base - physical_base;
ENTRY(_start)
SECTIONS
{
. = virtual_base;
_start_text = .;
.text : AT (ADDR(.text) - offset) { crt0.o(.text) *(.text) }
/* rodata is needed else your strings will link at physical! */
.rodata : AT (ADDR(.rodata) - offset) { *(.rodata) }
.rodata1 : AT (ADDR(.rodata1) - offset) { *(.rodata1) }
.data : AT (ADDR(.data) - offset) { *(.data) }
.bss : AT (ADDR(.bss) - offset) { *(.bss) }
_end = .;
}

7
tasks/fs0/include/task.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef __FS0_TASK_H__
#define __FS0_TASK_H__
#define __TASKNAME__ "FS0"
#endif /* __FS0_TASK_H__ */

82
tasks/fs0/main.c Normal file
View File

@@ -0,0 +1,82 @@
/*
* FS0. Filesystem implementation
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <stdio.h>
#include <string.h>
#include <l4lib/arch/message.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/kip.h>
#include <l4lib/utcb.h>
#include <l4lib/ipcdefs.h>
#include <fs.h>
/* Synchronise with pager via a `wait' tagged ipc with destination as pager */
void wait_pager(l4id_t partner)
{
u32 tag = L4_IPC_TAG_WAIT;
printf("Going to wait till pager finishes dumping.\n");
l4_ipc(partner, l4_nilthread, tag);
printf("Pager synced with us.\n");
}
void fs_request_handler(struct fs_request *fsreq)
{
}
void handle_fs_requests(void)
{
u32 mr[MR_UNUSED_TOTAL];
l4id_t sender;
int err;
u32 tag;
printf("%s: Listening requests.\n", __TASKNAME__);
if ((err = l4_receive(L4_ANYTHREAD)) < 0) {
printf("%s: %s: IPC Error: %d. Quitting...\n", __TASKNAME__,
__FUNCTION__, err);
BUG();
}
/* Read conventional ipc data */
tag = l4_get_tag();
sender = l4_get_sender();
/* Read mrs not used by syslib */
for (int i = 0; i < MR_UNUSED_TOTAL; i++)
mr[i] = read_mr(i);
switch(tag) {
case L4_IPC_TAG_WAIT:
printf("%s: Synced with waiting thread.\n", __TASKNAME__);
break;
case L4_IPC_TAG_OPEN:
sys_open(sender, (void *)mr[0], (int)mr[1], (u32)mr[2]);
break;
case L4_IPC_TAG_READ:
sys_read(sender, (int)mr[0], (void *)mr[1], (int)mr[2]);
break;
case L4_IPC_TAG_WRITE:
sys_write(sender, (int)mr[0], (void *)mr[1], (int)mr[2]);
break;
case L4_IPC_TAG_LSEEK:
sys_lseek(sender, (int)mr[0], (int)mr[1], (int)mr[2]);
break;
default:
printf("%s: Unrecognised ipc tag (%d)"
"received. Ignoring.\n", __TASKNAME__, mr[MR_TAG]);
}
}
void main(void)
{
wait_pager(PAGER_TID);
while (1) {
handle_fs_requests();
}
}

0
tasks/fs0/src/dentry.c Normal file
View File

63
tasks/fs0/src/kdata.c Normal file
View File

@@ -0,0 +1,63 @@
/*
* Requesting system information from kernel during init.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <stdio.h>
#include <l4lib/arch/syscalls.h>
#include <kdata.h>
#include <string.h>
#include INC_API(kip.h)
#include <kmalloc/kmalloc.h>
/* Kernel data acquired during initialisation */
struct initdata initdata;
#define BOOTDESC_PREALLOC_SIZE 128
static char bootdesc_memory[BOOTDESC_PREALLOC_SIZE]; /* 128 bytes */
void print_bootdesc(struct bootdesc *bd)
{
for (int i = 0; i < bd->total_images; i++) {
printf("Task Image: %d\n", i);
printf("Name: %s\n", bd->images[i].name);
printf("Start: 0x%x\n", bd->images[i].phys_start);
printf("End: 0x%x\n", bd->images[i].phys_end);
}
}
int request_initdata(struct initdata *initdata)
{
int err;
int bootdesc_size;
/* Read the boot descriptor size */
if ((err = l4_kread(KDATA_BOOTDESC_SIZE, &bootdesc_size)) < 0) {
printf("L4_kdata_read() call failed. Could not complete"
"KDATA_BOOTDESC_SIZE request.\n");
goto error;
}
if (bootdesc_size > BOOTDESC_PREALLOC_SIZE) {
printf("Insufficient preallocated memory for bootdesc. "
"Size too big.\n");
goto error;
}
/* Get preallocated bootdesc memory */
initdata->bootdesc = (struct bootdesc *)&bootdesc_memory;
/* Read the boot descriptor */
if ((err = l4_kread(KDATA_BOOTDESC, initdata->bootdesc)) < 0) {
printf("L4_kdata_read() call failed. Could not complete"
"KDATA_BOOTDESC request.\n");
goto error;
}
return 0;
error:
printf("FATAL: %s failed during initialisation. exiting.\n", __TASKNAME__);
return err;
}

0
tasks/fs0/src/mount.c Normal file
View File

View File

@@ -0,0 +1,86 @@
#include <stdio.h>
#include <block.h>
#include <l4/lib/math.h>
#include <l4/macros.h>
#include <l4/types.h>
#include INC_GLUE(memory.h)
/*
* Romfs superblock descriptor:
*
* All words are Big-Endian.
*
* Word 0: | - | r | o | m |
* Word 1: | 1 | f | s | - |
* Word 2: | Size | The number of bytes in this fs.
* Word 3: | Checksum | The checksum of first 512 bytes.
* Word 4: | Volume Name | The name of volume, padded to 16-byte boundary.
* Rest: | File Headers | The rest of the data.
*/
struct romfs_superblock {
u32 word0;
u32 word1;
u32 size;
u32 checksum;
char name[0];
};
struct romfs_inode {
unsigned long mdata_size; /* Size of metadata */
unsigned long data_offset; /* Offset of data from start of fs */
};
static u32
romfs_checksum(void *data)
{
u32 sum = 0;
u32 *ptr = data;
size >>= 2;
while (size > 0) {
sum += be32_to_cpu(*ptr++);
size--;
}
return sum;
}
int romfs_fill_super(struct superblock *sb)
{
char buf[PAGE_SIZE];
struct romfs_superblock *romfs_sb = (struct romfs_superblock *)buf;
unsigned long vroot_offset;
struct vnode *vroot;
/* Read first page from block device */
bdev_readpage(0, buf);
/* Check superblock sanity */
if (strcmp(be32_to_cpu(romfs_sb->word0), ROMFS_SB_WORD0)) {
printf("Bad magic word 0\n");
}
if (strcmp(be32_to_cpu(romfs_sb->word1), ROMFS_SB_WORD1)) {
printf("Bad magic word 1\n");
}
if (romfs_checksum(romfs_sb, min(romfs_sb->size, PAGE_SIZE))) {
printf("Bad checksum.\n");
}
/* Copy some params to generic superblock */
sb->size = be32_to_cpu(romfs_sb->size);
sb->magic = ROMFS_MAGIC;
sb->ops = romfs_ops;
/* Offset of first vnode, which is the root vnode */
vroot_offset = align_up(strnlen(romfs_sb->name, ROMFS_MAXNAME) + 1, 16);
if (!(vroot = romfs_read_vnode(s, vroot_offset))) {
printf("Error, could not get root inode.\n");
}
/* Get the dirent for this vnode */
if (!(sb->root = new_dentry(vroot))) {
printf("Error: Could not get new dentry for root vnode.\n");
}
}

View File

@@ -0,0 +1,43 @@
#ifndef __ROMFS_H__
#define __ROMFS_H__
#define ROMFS_MAGIC 0x7275
#define ROMFS_FTYPE_MSK 0xF /* File mask */
#define ROMFS_FTYPE_HRD 0 /* Hard link */
#define ROMFS_FTYPE_DIR 1 /* Directory */
#define ROMFS_FTYPE_REG 2 /* Regular file */
#define ROMFS_FTYPE_SYM 3 /* Symbolic link */
#define ROMFS_FTYPE_BLK 4 /* Block device */
#define ROMFS_FTYPE_CHR 5 /* Char device */
#define ROMFS_FTYPE_SCK 6 /* Socket */
#define ROMFS_FTYPE_FIF 7 /* FIFO */
#define ROMFS_FTYPE_EXE 8 /* Executable */
#define ROMFS_NAME_ALIGN 16 /* Alignment size of names */
#define ROMFS_SB_WORD0 "-rom"
#define ROMFS_SB_WORD1 "1fs-"
/*
* Romfs superblock descriptor:
*
* All words are Big-Endian.
*
* Word 0: | - | r | o | m |
* Word 1: | 1 | f | s | - |
* Word 2: | Size | The number of bytes in this fs.
* Word 3: | Checksum | The checksum of first 512 bytes.
* Word 4: | Volume Name | The name of volume, padded to 16-byte boundary.
* Rest: | File Headers | The rest of the data.
*/
struct romfs_superblock {
u32 word0;
u32 word1;
u32 size;
u32 checksum;
char name[0];
};
#endif /* __ROMFS_H__ */

View File

@@ -0,0 +1,61 @@
#ifndef __LINUX_ROMFS_FS_H
#define __LINUX_ROMFS_FS_H
/* The basic structures of the romfs filesystem */
#define ROMBSIZE BLOCK_SIZE
#define ROMBSBITS BLOCK_SIZE_BITS
#define ROMBMASK (ROMBSIZE-1)
#define ROMFS_MAGIC 0x7275
#define ROMFS_MAXFN 128
#define __mkw(h,l) (((h)&0x00ff)<< 8|((l)&0x00ff))
#define __mkl(h,l) (((h)&0xffff)<<16|((l)&0xffff))
#define __mk4(a,b,c,d) cpu_to_be32(__mkl(__mkw(a,b),__mkw(c,d)))
#define ROMSB_WORD0 __mk4('-','r','o','m')
#define ROMSB_WORD1 __mk4('1','f','s','-')
/* On-disk "super block" */
struct romfs_super_block {
__be32 word0;
__be32 word1;
__be32 size;
__be32 checksum;
char name[0]; /* volume name */
};
/* On disk inode */
struct romfs_inode {
__be32 next; /* low 4 bits see ROMFH_ */
__be32 spec;
__be32 size;
__be32 checksum;
char name[0];
};
#define ROMFH_TYPE 7
#define ROMFH_HRD 0
#define ROMFH_DIR 1
#define ROMFH_REG 2
#define ROMFH_SYM 3
#define ROMFH_BLK 4
#define ROMFH_CHR 5
#define ROMFH_SCK 6
#define ROMFH_FIF 7
#define ROMFH_EXEC 8
/* Alignment */
#define ROMFH_SIZE 16
#define ROMFH_PAD (ROMFH_SIZE-1)
#define ROMFH_MASK (~ROMFH_PAD)
#ifdef __KERNEL__
/* Not much now */
#endif /* __KERNEL__ */
#endif

0
tasks/fs0/src/sb.c Normal file
View File

View File

@@ -0,0 +1,31 @@
/*
* A basic unix-like read/writeable filesystem.
*
* Copyright (C) 2007 Bahadir Balban
*/
#define SIMPLEFS_BLOCK_SIZE 1024
/*
* Simplefs superblock
*/
struct simplefs_sb {
unsigned long magic; /* Filesystem magic */
unsigned long ioffset; /* Offset of first inode */
unsigned long bsize; /* Fs block size */
};
struct simplefs_sb *sb;
static void simplefs_fill_super(struct superblock *sb)
{
char buf[SIMPLEFS_BLOCK_SIZE];
bdev_read(0, SIMPLEFS_BLOCK_SIZE, buf);
}
static void simplefs_read_vnode(struct vnode *)
{
}

28
tasks/fs0/src/vfs.c Normal file
View File

@@ -0,0 +1,28 @@
#include <stdio.h>
#include <l4/api/ipc.h>
#include <l4lib/kip.h>
#include <l4lib/arch/syscalls.h>
/* Simply calls a wait ipc to sync with the given partner thread */
void wait_task(l4id_t partner)
{
u32 tag = L4_IPC_TAG_WAIT;
l4_ipc(partner, l4_nilthread, tag);
printf("%d synced with us.\n", (int)partner);
}
void mount_root(void)
{
l4id_t blkdev_shmid;
/*
* We know the primary block device from compile-time.
* It is expected to have the root filesystem.
*/
wait_task(BLKDEV_TID);
/* Set up a shared memory area with the block device */
l4_receive_shm(
}

0
tasks/fs0/src/vnode.c Normal file
View File

View File

@@ -0,0 +1,27 @@
#!/usr/bin/python
import os
import sys
compiler_prefix = "arm-linux-"
objdump = "objdump"
command = "-t"
image_name = "roottask.axf"
linkoutput_file_suffix = "-linkinfo.txt"
linkoutput_file = image_name + linkoutput_file_suffix
def generate_bootdesc():
command = compiler_prefix + objdump + " -t " + image_name + " > " + linkoutput_file
print command
os.system(command)
f = open(linkoutput_file, "r")
while True:
line = f.readline()
if len(line) is 0:
break
if "_start" in line or "_end" in line:
print line
f.close()
if __name__ == "__main__":
generate_bootdesc()

78
tasks/libl4/SConstruct Normal file
View File

@@ -0,0 +1,78 @@
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import glob
import sys
from os.path import join
from string import split
project_root = "../.."
kernel_headers = join(project_root, "include")
config_h = join(project_root, "include/l4/config.h")
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
CCFLAGS = ['-g', '-nostdinc', '-nostdlib', '-ffreestanding'],
LINKFLAGS = ['-nostdlib'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc')
def extract_arch_subarch_plat(config_header):
'''
From the autogenerated kernel config.h, extracts platform, archictecture,
subarchitecture information. This is used to include the relevant headers
from the kernel directories.
'''
arch = None
subarch = None
plat = None
if not os.path.exists(config_header):
print "\n\nconfig.h does not exist. "\
"Please run: `scons configure' first\n\n"
sys.exit()
f = open(config_h, "r")
while True:
line = f.readline()
if line == "":
break
parts = split(line)
if len(parts) > 0:
if parts[0] == "#define":
if parts[1] == "__ARCH__":
arch = parts[2]
elif parts[1] == "__PLATFORM__":
plat = parts[2]
elif parts[1] == "__SUBARCH__":
subarch = parts[2]
f.close()
if arch == None:
print "Error: No config symbol found for architecture"
sys.exit()
if subarch == None:
print "Error: No config symbol found for subarchitecture"
sys.exit()
if plat == None:
print "Error: No config symbol found for platform"
sys.exit()
return arch, subarch, plat
def create_symlinks(arch):
if not os.path.exists("include/l4lib/arch"):
os.system("ln -s %s %s" % ("arch-" + arch, "include/l4lib/arch"))
arch, subarch, plat = extract_arch_subarch_plat(config_h)
create_symlinks(arch) # Creates symlinks to architecture specific directories.
headers = ["#include", "#include/libl4/arch", kernel_headers]
env.Append(CPPPATH = headers)
src = glob.glob("src/*.c") + glob.glob("src/%s/*.[cS]" % arch)
libl4 = env.StaticLibrary('l4', src)

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
#ifndef __ARM_MESSAGE_H__
#define __ARM_MESSAGE_H__
#include <l4lib/types.h>
#include <l4lib/arch/utcb.h>
/* Functions to read/write utcb registers */
static inline unsigned int read_mr(int offset)
{
return __L4_ARM_Utcb()->mr[offset];
}
static inline void write_mr(unsigned int val, unsigned int offset)
{
__L4_ARM_Utcb()->mr[offset] = val;
}
/* Tag definitions */
#define L4_TAG_PFLAG (1 << 12) /* Propagation */
#define L4_TAG_NFLAG (1 << 13) /* Notify */
#define L4_TAG_RFLAG (1 << 14) /* Block-on-receive */
#define L4_TAG_SFLAG (1 << 15) /* Block-on-send */
#define L4_TAG_XFLAG (1 << 14) /* Crosscall (inter-cpu ipc) */
#define L4_TAG_EFLAG (1 << 15) /* Error */
#endif /* __ARM_MESSAGE_H__ */

View File

@@ -0,0 +1,83 @@
/*
* System call prototypes.
*
* Copyright (C) 2007 Bahadir Balban
*/
#ifndef __ARM_SYSCALLS_H__
#define __ARM_SYSCALLS_H__
#include <l4lib/arch/types.h>
#include <l4lib/arch/vregs.h>
#include <l4lib/arch/message.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>
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_getpid;
int l4_getid(struct task_ids *ids);
typedef int (*__l4_ipc_t)(l4id_t to, l4id_t from, u32 tag);
extern __l4_ipc_t __l4_ipc;
int l4_ipc(l4id_t to, l4id_t from, u32 tag);
typedef int (*__l4_kread_t)(u32 rd, void *addr);
extern __l4_kread_t __l4_kread;
int l4_kread(u32 rd, void *addr);
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_space_control_t)(unsigned int action, void *kdata);
extern __l4_space_control_t __l4_space_control;
int l4_space_control(unsigned int action, void *kdata);
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)(unsigned int pc, unsigned int sp,
l4id_t pager, l4id_t tid);
extern __l4_exchange_registers_t __l4_exchange_registers;
int l4_exchange_registers(unsigned int pc, unsigned int sp, int pager, l4id_t tid);
typedef int (*__l4_kmem_reclaim_t)(unsigned long *pfn, int *npages);
extern __l4_kmem_reclaim_t __l4_kmem_reclaim;
int l4_kmem_reclaim(unsigned long *pfn, int *npages);
typedef int (*__l4_kmem_grant_t)(unsigned long pfn, int npages);
extern __l4_kmem_grant_t __l4_kmem_grant;
int l4_kmem_grant(unsigned long pfn, int npages);
/* To be supplied by server tasks. */
void *virt_to_phys(void *);
void *phys_to_virt(void *);
#endif /* __ARM_SYSCALLS_H__ */

View File

@@ -0,0 +1,179 @@
/*
* Helper functions that wrap raw l4 syscalls.
*
* Copyright (C) 2007 Bahadir 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)
/*
* Servers get sender.
*/
static inline l4id_t l4_get_sender(void)
{
return (l4id_t)read_mr(MR_SENDER);
}
static inline void l4_set_sender(l4id_t id)
{
write_mr(MR_SENDER, (unsigned int)id);
}
static inline unsigned int l4_get_tag(void)
{
return read_mr(MR_TAG);
}
static inline void l4_set_tag(unsigned int tag)
{
write_mr(MR_TAG, tag);
}
static inline l4id_t self_tid(void)
{
struct task_ids ids;
l4_getid(&ids);
return ids.tid;
}
static inline int l4_send(l4id_t to, unsigned int tag)
{
l4_set_tag(tag);
l4_set_sender(self_tid());
return l4_ipc(to, L4_NILTHREAD, 0);
}
static inline int l4_sendrecv(l4id_t to, l4id_t from, unsigned int tag)
{
BUG_ON(to == L4_NILTHREAD || from == L4_NILTHREAD);
l4_set_tag(tag);
l4_set_sender(self_tid());
return l4_ipc(to, from, 0);
}
static inline int l4_receive(l4id_t from)
{
return l4_ipc(L4_NILTHREAD, from, 0);
}
/* 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);
}
/* Servers:
* Return the ipc result back to requesting task.
*/
static inline int l4_ipc_return(int retval)
{
unsigned int tag = l4_get_tag();
l4id_t sender = l4_get_sender();
l4_set_retval(retval);
return l4_send(sender, tag);
}
/* 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;
l4_getid(&ids);
l4_map(phys, phys_to_virt(phys), npages, MAP_USR_RW_FLAGS, ids.tid);
return phys_to_virt(phys);
}
/* 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);
return virt_to_phys(virt);
}
/*
* A helper to produce grant ipc between a pager and its client, or a
* synchronous syscall to the kernel in case the grant is to the kernel.
*/
static inline int l4_grant_pages(unsigned long pfn, int npages, l4id_t tid)
{
/* Only a pager can grant pages to kernel. */
if (tid == KERNEL_TID) {
/* Granting physical pages via a system call in kernel case. */
return l4_kmem_grant(pfn, npages);
} else {
/*
* FIXME: This should set up appropriate message registers and
* call l4_ipc() on the target thread. Pages given are virtual.
*/
while(1);
}
return 0;
}
/*
* NOTE: This is just brainstroming yet.
* A helper to reclaim unused pages. A pager can reclaim pages from kernel or
* other tasks this way.
*/
static inline int l4_reclaim_pages(l4id_t tid)
{
unsigned long pfn;
int npages;
if (tid == KERNEL_TID) {
/*
* A single contiguous sequence of physical pages are returned
* by kernel via a syscall. Simpler the better for now.
*/
l4_kmem_reclaim(&pfn, &npages);
} else {
/*
* An ipc to a task where pfn and npages come in message regs.
*/
while(1);
}
return 0;
}
#endif /* __L4LIB_SYSLIB_H__ */

View File

@@ -0,0 +1,12 @@
#ifndef __L4_ARCH_ARM__
#define __L4_ARCH_ARM__
#define TASK_ID_INVALID -1
struct task_ids {
int tid;
int spid;
};
#include <l4/arch/arm/types.h>
#endif

View File

@@ -0,0 +1,43 @@
#ifndef __ARM_UTCB_H__
#define __ARM_UTCB_H__
#include <l4lib/types.h>
#include <l4lib/arch/vregs.h>
/* FIXME: LICENSE/LICENCE */
/*
* NOTE: In syslib.h the first few mrs are used by data frequently
* needed for all ipcs. Those mrs are defined here.
*/
/* MRs always used on receive by syslib */
#define MR_RETURN 0 /* Contains the posix return value. */
/* MRs always used on send by syslib */
#define MR_TAG 0 /* Defines the message purpose */
#define MR_SENDER 1 /* For anythread receivers to discover sender */
/* These define the mr start - end range that aren't used by syslib */
#define MR_UNUSED_START 2 /* The first mr that's not used by syslib.h */
#define MR_TOTAL 6
#define MR_UNUSED_TOTAL (MR_TOTAL - MR_UNUSED_START)
/* Compact utcb for now! :-) */
struct utcb {
u32 mr[MR_TOTAL];
u32 tid; /* Thread id */
/*
* This field is used by servers as the ptr to current tcb,
* i.e. the task that this server is serving to.
*/
unsigned long usr_handle;
};
static inline struct utcb *__L4_ARM_Utcb()
{
return (struct utcb *)(*(struct utcb **)USER_UTCB_REF);
}
#endif /* __ARM_UTCB_H__ */

View File

@@ -0,0 +1,13 @@
/*
* Copyright (C) 2007 Bahadir Balban
*/
#ifndef __L4_ARM_VREGS_H__
#define __L4_ARM_VREGS_H__
/* FIXME: LICENSE/LICENCE */
#define USER_UTCB_REF 0xFF000FF0
#define L4_KIP_ADDRESS 0xFF000000
#define UTCB_KIP_OFFSET 0xFF0
#endif /* __L4_ARM_VREGS_H__ */

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2007 Bahadir Balban
*
* This file contains ipc definitions that are needed for server tasks
* to communicate with each other. For example common shared memory ids
* between two servers, or common ipc tags used between two servers are
* defined here.
*/
#ifndef __IPCDEFS_H__
#define __IPCDEFS_H__
#include <l4/api/ipc.h>
/* SHMID used betweeen FS0 and BLKDEV0 servers */
#define FS_BLKDEV_SHMID 0
/*** IPC Tags used between server tasks ***/
/* For ping ponging */
#define L4_IPC_TAG_PINGPONG 3
/* To negotiate a shared memory mapping */
#define L4_IPC_TAG_SHM 4
/* To negotiate a grant mapping */
#define L4_IPC_TAG_GRANT 5
/* Posix system call tags */
#define L4_IPC_TAG_SHMGET 6
#define L4_IPC_TAG_SHMAT 7
#define L4_IPC_TAG_SHMDT 8
#define L4_IPC_TAG_MMAP 9
#define L4_IPC_TAG_MUNMAP 10
#define L4_IPC_TAG_MSYNC 11
#define L4_IPC_TAG_OPEN 12
#define L4_IPC_TAG_READ 13
#define L4_IPC_TAG_WRITE 14
#define L4_IPC_TAG_LSEEK 15
#define L4_IPC_TAG_CLOSE 16
#endif /* __IPCDEFS_H__ */

View File

@@ -0,0 +1,15 @@
/*
* Kernel Interface Page
*
* Copyright (C) 2007 Bahadir Balban
*
*/
#ifndef __L4LIB_KIP_H__
#define __L4LIB_KIP_H__
/* Use the kernel header */
#include <l4lib/types.h>
#include <l4lib/arch/syscalls.h>
#include <l4/api/kip.h>
#endif /* __KIP_H__ */

View File

@@ -0,0 +1,17 @@
#ifndef __TYPES_H__
#define __TYPES_H__
/* Copyright (C) 2003 - 2004 NICTA */
#include <l4lib/arch/types.h>
#define l4_nilpage 0
#define l4_nilthread -1
#define l4_anythread -2
#define l4_niltag 0
#define l4_notifytag (1 << 13)
#define l4_waittag (1 << 14)
#endif /* __TYPES_H__ */

View File

@@ -0,0 +1,10 @@
/*
* Copyright (C) 2007 Bahadir Balban
*/
#ifndef __UTCB_H__
#define __UTCB_H__
#include <l4lib/types.h>
#include <l4lib/arch/utcb.h>
#endif /* __UTCB_H__ */

View File

@@ -0,0 +1,157 @@
/*
* Userspace system call interface.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4lib/arch/asm.h>
#include <l4lib/arch/vregs.h>
#include <l4/generic/space.h>
.macro utcb_address rx
mov \rx, #L4_KIP_ADDRESS
add \rx, \rx, #UTCB_KIP_OFFSET
ldr \rx, [\rx]
.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)
/*
* Reads data from the kernel into given buffer. Data is defined by request descriptor.
* @r0 = request descriptor, @r1 = buffer address.
*/
BEGIN_PROC(l4_kread)
ldr r12, =__l4_kread
ldr pc, [r12] @ Jump into the SWI
/*
* The LR_USR points at the return address of this function. The system
* call return path directly jumps to LR_USR so we don't even need a
* return instruction here.
*/
END_PROC(l4_kread)
/*
* Inter-process communication. Loads message registers as arguments before the call,
* and stores them as results after the call. @r0 = to, @r1 = from, @r2 = tag.
*/
BEGIN_PROC(l4_ipc)
stmfd sp!, {r4-r8,lr} @ Save context.
utcb_address r12 @ Get utcb address.
ldmib r12!, {r3-r8} @ Load 5 Message registers from utcb. MR1-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)
/*
* 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 grants a set of pages to the kernel.
* @r0 = physical pfn, @r1 = number of pages
*/
BEGIN_PROC(l4_kmem_grant)
stmfd sp!, {lr}
ldr r12, =__l4_kmem_grant
mov lr, pc
ldr pc, [r12]
ldmfd sp!, {pc} @ Restore original lr and return.
END_PROC(l4_kmem_grant)
/*
* System call that reclaims a set of pages from the kernel.
* @r0 = ptr to physical pfn, @r1 = ptr to number of pages
*/
BEGIN_PROC(l4_kmem_reclaim)
stmfd sp!, {lr}
ldr r12, =__l4_kmem_reclaim
mov lr, pc
ldr pc, [r12]
ldmfd sp!, {pc} @ Restore original lr and return.
END_PROC(l4_kmem_reclaim)
/*
* System call that controls thread creation, destruction and modification.
* @r0 = thread action, @r1 = &ids
*/
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 = struct shm_kdata *kdata
*/
BEGIN_PROC(l4_space_control)
stmfd sp!, {lr}
ldr r12, =__l4_space_control
mov lr, pc
ldr pc, [r12]
ldmfd sp!, {pc} @ Restore original lr and return.
END_PROC(l4_space_control)
/*
* Sets registers of a thread and its pager.
* @r0 = pc to set, @r1 = sp to set @r2 = pager id, @r3 = 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)

40
tasks/libl4/src/init.c Normal file
View File

@@ -0,0 +1,40 @@
/*
* Initialise system call offsets.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4lib/kip.h>
__l4_ipc_t __l4_ipc = 0;
__l4_map_t __l4_map = 0;
__l4_unmap_t __l4_unmap = 0;
__l4_kread_t __l4_kread = 0;
__l4_getid_t __l4_getid = 0;
__l4_thread_switch_t __l4_thread_switch = 0;
__l4_thread_control_t __l4_thread_control = 0;
__l4_ipc_control_t __l4_ipc_control = 0;
__l4_space_control_t __l4_space_control = 0;
__l4_exchange_registers_t __l4_exchange_registers = 0;
__l4_kmem_grant_t __l4_kmem_grant = 0;
__l4_kmem_reclaim_t __l4_kmem_reclaim = 0;
struct kip *kip;
void __l4_init(void)
{
kip = l4_kernel_interface(0, 0, 0);
__l4_ipc = (__l4_ipc_t)kip->ipc;
__l4_map = (__l4_map_t)kip->map;
__l4_unmap = (__l4_unmap_t)kip->unmap;
__l4_kread = (__l4_kread_t)kip->kread;
__l4_getid = (__l4_getid_t)kip->getid;
__l4_thread_switch =(__l4_thread_switch_t)kip->thread_switch;
__l4_thread_control=(__l4_thread_control_t)kip->thread_control;
__l4_ipc_control= (__l4_ipc_control_t)kip->ipc_control;
__l4_space_control=(__l4_space_control_t)kip->space_control;
__l4_exchange_registers =(__l4_exchange_registers_t)kip->exchange_registers;
__l4_kmem_grant =(__l4_kmem_grant_t)kip->kmem_grant;
__l4_kmem_reclaim =(__l4_kmem_reclaim_t)kip->kmem_reclaim;
}

20
tasks/libl4/tagfilelist Normal file
View File

@@ -0,0 +1,20 @@
./src/init.c
./include/l4lib/kip.h
./include/l4lib/posix/l4shm.h
./include/l4lib/arch-arm/asm.h
./include/l4lib/arch-arm/types.h
./include/l4lib/arch-arm/utcb.h
./include/l4lib/arch-arm/syscalls.h
./include/l4lib/arch-arm/message.h
./include/l4lib/arch-arm/vregs.h
./include/l4lib/types.h
./include/l4lib/ipcdefs.h
./include/l4lib/utcb.h
./include/l4lib/examples/ipc.h
./include/l4lib/examples/message_stuff.h
./include/l4lib/examples/space.h
./include/l4lib/examples/thread.h
./include/l4lib/examples/syscalls.h
./include/l4lib/examples/message.h
./include/l4lib/examples/schedule.h
./src/arm/syscalls.S

67
tasks/libmem/SConstruct Normal file
View File

@@ -0,0 +1,67 @@
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import glob
import sys
from os.path import join
from string import split
project_root = "../.."
headers_root = join(project_root, "include/l4")
config_h = join(headers_root, "config.h")
#libl4 paths
libl4_headers = join(project_root, "tasks/libl4/include")
libl4_libpath = join(project_root, "tasks/libl4")
mm = "mm"
kmalloc = "kmalloc"
memcache = "memcache"
tests = "tests"
mm_dir = mm
kmalloc_dir = kmalloc
memcache_dir = memcache
tests_dir = tests
test_env = Environment(CC = 'gcc -m32',
CCFLAGS = ['-g', '-std=gnu99', '-Wall', '-Werror'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = ['gcc', 'mm', 'km', 'mc'],
LIBPATH = ['#'],
CPPPATH = ['#include', join(project_root, "include"), "#", libl4_headers])
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
CCFLAGS = ['-g', '-nostdlib', '-Wall', '-Werror', '-ffreestanding', '-std=gnu99'],
LINKFLAGS = ['-nostdlib'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc',
CPPPATH = [join(project_root, "include"), "#", libl4_headers])
if os.path.exists(config_h) is False:
print "\nThis build requires a valid kernel configuration header."
print "Please run `scons configure' in the kernel root directory."
print "Choose the `tests' target to build memory allocator tests,"
print "or any other target for real use.\n"
sys.exit()
mm_src = glob.glob("%s/*.c" % mm_dir)
kmalloc_src = glob.glob("%s/*.c" % kmalloc_dir)
memcache_src = glob.glob("%s/*.c" % memcache_dir)
tests_src = glob.glob ("%s/*.c" % tests_dir)
if "tests" in COMMAND_LINE_TARGETS:
print "WARNING!!! Did you configure the kernel with test target first???"
libmm = test_env.StaticLibrary(mm, mm_src)
libkmalloc = test_env.StaticLibrary("km", kmalloc_src)
libmemcache = test_env.StaticLibrary("mc", memcache_src)
test_prog = test_env.Program("test", tests_src)
env.Alias("tests", test_prog)
else:
libmm = env.StaticLibrary(mm, mm_src)
libkmalloc = env.StaticLibrary("km", kmalloc_src)
libmemcache = env.StaticLibrary("mc", memcache_src)

View File

@@ -0,0 +1,363 @@
/*
* Simple linked-list based kernel memory allocator.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <stdio.h>
#include <string.h>
#include <l4/config.h>
#include <l4/macros.h>
#include <l4/types.h>
#include INC_GLUE(memory.h)
#include INC_GLUE(memlayout.h)
#include INC_SUBARCH(mm.h)
#include <l4lib/arch/syscalls.h>
#include <l4/lib/list.h>
#include <kmalloc/kmalloc.h>
#include <mm/alloc_page.h>
/* Initial free area descriptor.
*
* Basic description of how free areas are tracked:
*
* A km_area marked with pg_alloc_pages means it is located at the beginning
* of a new page allocation, and it is the first struct to describe those
* allocated page(s).
*
* If, for all subpage_areas, pg_alloc_pages = {SA, SB, ..., SZ}, and `fragments
* of pg_alloc_pages' = {sa(n), sb(n), ..., sz(n)} where n is the sequence number
* of that fragment, and for each SX, SX = sx(1), and "->" denotes "next"
* pointer relationship, on a random occasion, the areas could look like this:
*
* SA->sa(2)->sa(3)->SB->sb(2)->SC->SD->SE->se(2)->se(3)->se(4)
*
* With regard to all alloc/free functions defined below, in this example's
* context, sa(1..3) can merge if any adjacent pair of them are free. Whereas if
* adjacent(SC,SD) were true, SC and SD cannot be merged even if they are both
* free, because they are pg_alloc_pages. Also, for each SX, it can be freed IFF
* it is the only element in SX, and it is free. For instance, each of SC or SD
* can be individually freed, provided they are marked unused.
*
* We could have used a bucket for each, e.g:
*
* SA->sa(2)->sa(3)
* |
* v
* SB->sb(2)->sb(3)
* |
* v
* SC
* |
* v
* SD
*
* etc. But the original is simple enough for now and does the job.
*
*/
struct list_head km_area_start;
/*
* Initialises a km_area descriptor according to the free area parameters
* supplied along with it. @ppage = pointer to start of free memory.
* @npages = number of pages the region contains. @km_areas = head of the list
* of km_areas on the system that belongs to kmalloc.
*/
void kmalloc_add_new_pages(void *ppage, int npages, struct list_head *km_areas)
{
struct km_area *new = (struct km_area *)ppage;
new->vaddr = (unsigned long)ppage + sizeof(struct km_area);
new->size = (npages * PAGE_SIZE) - sizeof(struct km_area);
new->used = 0;
new->pg_alloc_pages = npages;
INIT_LIST_HEAD(&new->list);
/*
* The first entry is a pg_alloc_pages. Adding the new pg_alloc_pages
* in tail ensures each pg_alloc_pages are adjacent, and their
* children are never intermixed.
*/
list_add_tail(&new->list, km_areas);
}
#define KM_INIT_PAGES 3
void kmalloc_init()
{
/* Initially allocated pages with one big free km_area */
void *ppage = l4_map_helper(alloc_page(KM_INIT_PAGES),
KM_INIT_PAGES);
struct km_area *new = (struct km_area *)ppage;
BUG_ON(!new);
new->vaddr = (unsigned long)ppage + sizeof(struct km_area);
new->size = (KM_INIT_PAGES * PAGE_SIZE)
- sizeof(struct km_area);
new->used = 0;
new->pg_alloc_pages = KM_INIT_PAGES;
INIT_LIST_HEAD(&new->list);
INIT_LIST_HEAD(&km_area_start);
/* Add the first area to the global list head */
list_add(&new->list, &km_area_start);
/* NOTE: If needed, initialise mutex here */
}
/*
* Given a free list, finds a free region of requested size plus one subpage
* area descriptor. Allocates and initialises the new descriptor, adds it to
* the list and returns it.
*/
static struct km_area *
find_free_km_area(int size, struct list_head *km_areas)
{
struct km_area *new;
struct km_area *area;
const unsigned long alignment_extra_max = SZ_WORD - 1;
int alignment_used = 0, alignment_unused = 0;
/* The minimum size needed if the area will be divided into two */
int dividable_size = size + sizeof(struct km_area)
+ alignment_extra_max;
list_for_each_entry (area, km_areas, list) {
/* Is this a free region that fits? */
if ((area->size) >= dividable_size && !area->used) {
unsigned long addr, addr_aligned;
/*
* Cut the free area from the end, as much as
* we want to use
*/
area->size -= size + sizeof(struct km_area);
addr = (area->vaddr + area->size);
addr_aligned = align_up(addr, SZ_WORD);
alignment_used = addr_aligned - addr;
alignment_unused = alignment_extra_max
- alignment_used;
/*
* Add the extra bit that's skipped for alignment
* to original subpage
*/
area->size += alignment_used;
/*
* Allocate the new link structure at the end
* of the free area shortened previously.
*/
new = (struct km_area *)addr_aligned;
/*
* Actual allocated memory starts after subpage
* descriptor
*/
new->vaddr = (unsigned long)new
+ sizeof(struct km_area);
new->size = size + sizeof(struct km_area)
+ alignment_unused;
new->used = 1;
/* Divides other allocated page(s) */
new->pg_alloc_pages = 0;
/* Add used region to the page area list */
INIT_LIST_HEAD(&new->list);
list_add(&new->list, &area->list);
return new;
} else if (area->size < dividable_size &&
area->size >= size && !area->used) {
/*
* Area not at dividable size but can satisfy request,
* so it's simply returned.
*/
area->used = 1;
return area;
}
}
/* Traversed all areas and can't satisfy request. */
return 0;
}
/*
* Allocate, initialise a km_area along with its free memory of minimum
* size as @size, and add it to km_area list.
*/
static int
kmalloc_get_free_pages(int size, struct list_head *km_areas)
{
int totalsize = size + sizeof(struct km_area) * 2;
int npages = totalsize / PAGE_SIZE;
void *ppage;
if (totalsize & PAGE_MASK)
npages++;
if ((ppage = l4_map_helper(alloc_page(npages), npages)) == 0)
/* TODO: Return specific error code, e.g. ENOMEM */
return -1;
BUG_ON((npages * PAGE_SIZE) < (size + sizeof(struct km_area)));
kmalloc_add_new_pages(ppage, npages, km_areas);
return 0;
}
/*
* Linked list based kernel memory allocator. This has the simplicity of
* allocating list structures together with the requested memory area. This
* can't be done with the page allocator, because it works in page-size chunks.
* In kmalloc we can allocate more fine-grain sizes, so a link structure can
* also be embedded together with requested data.
*/
/* Allocates given @size, requests more free pages if free areas depleted. */
void *kmalloc(int size)
{
struct km_area *new_area;
void *allocation;
/* NOTE: If needed, lock mutex here */
new_area = find_free_km_area(size, &km_area_start);
if (!new_area) {
if (kmalloc_get_free_pages(size, &km_area_start) < 0) {
allocation = 0;
goto out;
}
else
new_area = find_free_km_area(size, &km_area_start);
}
BUG_ON(!new_area);
allocation = (void *)new_area->vaddr;
out:
/* NOTE: If locked, unlock mutex here */
return allocation;
}
/* kmalloc with zero initialised memory */
void *kzalloc(int size)
{
void *mem = kmalloc(size);
if (mem)
memset(mem, 0, size);
return mem;
}
void km_free_empty_pages(struct km_area *free_area)
{
unsigned long wholesize;
/* Not allocated from page allocator */
if (!free_area->pg_alloc_pages)
return;
/* The first km_area in memory from the page allocator: */
/* Must be on a page boundary */
BUG_ON((unsigned long)free_area & PAGE_MASK);
/* Must be unused */
BUG_ON(free_area->used);
/* Must be whole, (i.e. not divided into other km_areas) */
wholesize = free_area->pg_alloc_pages * PAGE_SIZE;
if ((free_area->size + sizeof(struct km_area)) < wholesize)
return;
/* Must have at least PAGE_SIZE size, when itself included */
BUG_ON(free_area->size < (PAGE_SIZE - sizeof(struct km_area)));
/* Its size must be a multiple of PAGE_SIZE, when itself included */
if ((free_area->size + sizeof(struct km_area)) & PAGE_MASK) {
printk("Error: free_area->size: 0x%lu, with km_area_struct:"
" 0x%lu, PAGE_MASK: 0x%x\n", free_area->size,
free_area->size + sizeof(struct km_area), PAGE_MASK);
BUG();
}
list_del(&free_area->list);
/* And finally must be freed without problems */
BUG_ON(free_page(l4_unmap_helper(free_area, __pfn(wholesize))) < 0);
return;
}
struct km_area *km_merge_free_areas(struct km_area *before,
struct km_area *after)
{
/*
* If `after' has pg_alloc_pages set, it means it can't be merged and
* has to be returned explicitly to the page allocator.
*/
if (after->pg_alloc_pages)
return 0;
BUG_ON(before->vaddr + before->size != after->vaddr);
BUG_ON(before->used || after->used)
BUG_ON(before == after);
/*
* km_area structures are at the beginning of the memory
* areas they describe. By simply merging them with another
* area they're effectively freed.
*/
before->size += after->size + sizeof(struct km_area);
list_del(&after->list);
return before;
}
int find_and_free_km_area(void *vaddr, struct list_head *areas)
{
struct km_area *area, *prev, *next, *merged;
if (!vaddr) /* A well-known invalid address */
return -1;
list_for_each_entry(area, areas, list)
if (area->vaddr == (unsigned long)vaddr && area->used)
goto found;
/* Area not found */
return -1;
found:
area->used = 0;
/* Now merge with adjacent areas if possible */
if (area->list.prev != areas) {
prev = list_entry(area->list.prev, struct km_area, list);
if (!prev->used)
if ((merged = km_merge_free_areas(prev, area)))
area = merged;
}
if (area->list.next != areas) {
next = list_entry(area->list.next, struct km_area, list);
if (!next->used)
if ((merged = km_merge_free_areas(prev, area)))
area = merged;
}
/*
* After freeing and all possible merging, try returning region back
* to page allocator.
*/
km_free_empty_pages(area);
return 0;
}
int kfree(void *virtual)
{
int ret;
/* NOTE: If needed, lock mutex here */
ret = find_and_free_km_area(virtual, &km_area_start);
/* NOTE: If locked, unlock mutex here */
return ret;
}

View File

@@ -0,0 +1,457 @@
/*
* Kernel memory allocator.
*
* Copyright (C) 2007 Bahadir Balban
*
*/
#include <stdio.h>
#include <string.h>
#include <l4/config.h>
#include <l4/macros.h>
#include <l4/types.h>
#include INC_GLUE(memory.h)
#include INC_GLUE(memlayout.h)
#include INC_SUBARCH(mm.h)
#include <l4lib/arch/syscalls.h>
#include <l4/lib/list.h>
#include <kmalloc/kmalloc.h>
#include <mm/alloc_page.h>
/* Initial free area descriptor.
*
* Basic description of how free areas are tracked:
*
* A subpage_area marked as head_of_pages means it is located at the beginning
* of a new page allocation, and it is the first struct to describe those
* allocated page(s).
*
* If, for all subpage_areas, head_of_pages = {SA, SB, ..., SZ}, and `fragments
* of head_of_pages' = {sa(n), sb(n), ..., sz(n)} where n is the sequence number
* of that fragment, and for each SX, SX = sx(1), and "->" denotes "next"
* pointer relationship, on a random occasion, the areas could look like this:
*
* SA->sa(2)->sa(3)->SB->sb(2)->SC->SD->SE->se(2)->se(3)->se(4)
*
* With regard to all alloc/free functions defined below, in this example's
* context, sa(1..3) can merge if any adjacent pair of them are free. Whereas if
* adjacent(SC,SD) were true, SC and SD cannot be merged even if they are both
* free, because they are head_of_pages. Also, for each SX, it can be freed IFF
* it is the only element in SX, and it is free. For instance, each of SC or SD
* can be individually freed, provided they are marked unused.
*
* We could have used a bucket for each, e.g:
*
* SA->sa(2)->sa(3)
* |
* v
* SB->sb(2)->sb(3)
* |
* v
* SC
* |
* v
* SD
*
* etc. But the original is simple enough for now and does the job.
*
*/
struct subpage_area km_areas;
/* Initialises a subpage area descriptor according to the free area parameters
* supplied along with it. @ppage = pointer to start of free memory.
* @npages = number of pages the region contains. @areas = head of the list of
* subpage_areas on the system that belongs to kmalloc. */
void kmalloc_add_new_pages(void *ppage, int npages, struct subpage_area **areas)
{
struct subpage_area *new = (struct subpage_area *)ppage;
new->vaddr = (unsigned int)ppage + sizeof(struct subpage_area);
new->size = (npages * PAGE_SIZE) - sizeof(struct subpage_area);
new->used = 0;
new->head_of_pages = npages;
INIT_LIST_HEAD(&new->list);
/* The first entry is a head_of_pages. Adding the new head_of_pages
* in tail ensures each head_of_pages are adjacent, and their
* children are never intermixed */
list_add_tail(&new->list, &(*areas)->list);
}
#define KMALLOC_INITIAL_PAGES 3
void kmalloc_init()
{
/* Initially allocated pages with one big free km_area */
void *ppage = alloc_page(KMALLOC_INITIAL_PAGES);
ppage = l4_map_helper(ppage, KMALLOC_INITIAL_PAGES);
struct subpage_area *new = (struct subpage_area *)ppage;
BUG_ON(!new);
new->vaddr = (unsigned int)ppage + sizeof(struct subpage_area);
new->size = (KMALLOC_INITIAL_PAGES * PAGE_SIZE)
- sizeof(struct subpage_area);
new->used = 0;
new->head_of_pages = KMALLOC_INITIAL_PAGES;
INIT_LIST_HEAD(&new->list);
/* Assign the first area to global list pointer */
km_areas = new;
/* NOTE: If needed, initialise mutex here */
}
/* Given a free list, finds a free region of requested size plus one subpage
* area descriptor. Allocates and initialises the new descriptor, adds it to
* the list and returns it.
*/
static struct subpage_area *
find_free_subpage_area(int size, struct subpage_area **areas)
{
struct subpage_area *new;
struct subpage_area *cur = *areas;
const unsigned int alignment_extra_max = SZ_WORD - 1;
unsigned int alignment_used = 0, alignment_unused = 0;
/* The minimum size needed if the area will be divided into two */
int dividable_size = size + sizeof(struct subpage_area)
+ alignment_extra_max;
/* Is this a free region that fits? */
if ((cur->size) >= dividable_size && !cur->used) {
unsigned int addr, addr_aligned;
/* Cut the free area as much as we want to used */
cur->size -= size + sizeof(struct subpage_area);
addr = (cur->vaddr + cur->size);
addr_aligned = align_up(addr, SZ_WORD);
alignment_used = addr_aligned - addr;
alignment_unused = alignment_extra_max - alignment_used;
/* Add the extra bit that's skipped for alignment to original subpage */
cur->size += alignment_used;
/* Allocate the new link structure at the end
* of the free area shortened previously. */
new = (struct subpage_area *)addr_aligned;
/* Actual allocated memory starts after subpage descriptor */
new->vaddr = (unsigned int)new + sizeof(struct subpage_area);
new->size = size + sizeof(struct subpage_area) + alignment_unused;
new->used = 1;
new->head_of_pages = 0; /* Divides other allocated page(s) */
/* Add used region to the subpage_area list */
INIT_LIST_HEAD(&new->list);
list_add(&new->list, &cur->list);
return new;
} else if (cur->size < dividable_size &&
cur->size >= size && !cur->used) {
/* The area can't be divided, but has enough room for the
* actual allocation, it just misses the few bytes for a
* new subpage_area for splitting. In this case the current
* page area is simply marked used and returned. This is a
* rare but important case, because on-demand free page
* allocations don't ensure new free areas are sufficiently
* large to be divisable. */
cur->used = 1;
return cur;
}
/* Do the same for all other entries */
list_for_each_entry (cur, &(*areas)->list, list) {
/* Is this a free region that fits? */
if ((cur->size) >= dividable_size && !cur->used) {
unsigned int addr, addr_aligned;
/* Cut the free area from the end, as much as
* we want to use */
cur->size -= size + sizeof(struct subpage_area);
addr = (cur->vaddr + cur->size);
addr_aligned = align_up(addr, SZ_WORD);
alignment_used = addr_aligned - addr;
alignment_unused = alignment_extra_max
- alignment_used;
/* Add the extra bit that's skipped for alignment
* to original subpage */
cur->size += alignment_used;
/* Allocate the new link structure at the end
* of the free area shortened previously. */
new = (struct subpage_area *)addr_aligned;
/* Actual allocated memory starts after subpage
* descriptor */
new->vaddr = (unsigned int)new
+ sizeof(struct subpage_area);
new->size = size + sizeof(struct subpage_area)
+ alignment_unused;
new->used = 1;
/* Divides other allocated page(s) */
new->head_of_pages = 0;
/* Add used region to the page area list */
INIT_LIST_HEAD(&new->list);
list_add(&new->list, &cur->list);
return new;
} else if (cur->size < dividable_size &&
cur->size >= size && !cur->used) {
/* Area not at dividable size but can satisfy request,
* so it's simply returned. */
cur->used = 1;
return cur;
}
}
/* Traversed all areas and can't satisfy request. */
return 0;
}
/* Allocate, initialise a subpage area along with its free
* memory of minimum size as @size, and add it to subpage list. */
static int
kmalloc_get_free_pages(int size, struct subpage_area **areas)
{
int totalsize = size + sizeof(struct subpage_area) * 2;
int npages = totalsize / PAGE_SIZE;
void *ppage;
if (totalsize & PAGE_MASK)
npages++;
if ((ppage = l4_map_helper(alloc_page(npages), npages))
== 0)
/* TODO: Return specific error code, e.g. ENOMEM */
return -1;
BUG_ON((npages * PAGE_SIZE) < (size + sizeof(struct subpage_area)));
kmalloc_add_new_pages(ppage, npages, areas);
return 0;
}
/* Linked list based subpage allocator. This has the simplicity of allocating
* list structures together with the requested memory area. This can't be done
* with the page allocator, because it works in page-size chunks. In kmalloc
* we can allocate more fine-grain sizes, so a link structure can also be
* embedded together with requested data.
*/
/* Allocates given @size, requests more free pages if free areas depleted. */
void *kmalloc(int size)
{
struct subpage_area *new_area;
void *allocation;
/* NOTE: If needed, lock mutex here */
new_area = find_free_subpage_area(size, &km_areas);
if (!new_area) {
if (kmalloc_get_free_pages(size, &km_areas) < 0) {
allocation = 0;
goto out;
}
else
new_area = find_free_subpage_area(size, &km_areas);
}
BUG_ON(!new_area);
allocation = (void *)new_area->vaddr;
out:
/* NOTE: If locked, unlock mutex here */
return allocation;
}
/* kmalloc with zero initialised memory */
void *kzalloc(int size)
{
void *mem = kmalloc(size);
if (mem)
memset(mem, 0, size);
return mem;
}
void km_free_empty_pages(struct subpage_area *free_area,
struct subpage_area **start)
{
unsigned int wholesize;
if (!free_area->head_of_pages)
return; /* Not allocated from page allocator */
if (free_area == *start)
return; /* First subpage area is allocated at
initialisation and never deallocated */
/* A head of page: */
/* Can't be the only element, start is always there. */
BUG_ON(list_empty(&free_area->list));
/* Must be on a page boundary */
BUG_ON((unsigned int)free_area & PAGE_MASK);
/* Must be unused */
BUG_ON(free_area->used);
/* Furthermore, a head of page that can be freed must be whole:
* Total number of pages when as a whole, is kept in [31:1] */
wholesize = free_area->head_of_pages * PAGE_SIZE;
if ((free_area->size + sizeof(struct subpage_area)) < wholesize)
return;
/* Must have at least PAGE_SIZE size, when itself included */
BUG_ON(free_area->size < (PAGE_SIZE - sizeof(struct subpage_area)));
/* Its size must be a multiple of PAGE_SIZE, when itself included */
// BUG_ON((free_area->size + sizeof(struct subpage_area)) & PAGE_MASK);
if ((free_area->size + sizeof(struct subpage_area)) & PAGE_MASK) {
printk("Error: free_area->size: 0x%x, with subpage: 0x%x, PAGE_MASK: 0x%x\n",
free_area->size, free_area->size + sizeof(struct subpage_area), PAGE_MASK);
BUG();
}
list_del(&free_area->list);
/* And finally must be freed without problems */
if (free_page(l4_unmap_helper(free_area, wholesize)) < 0)
BUG();
return;
}
static int
km_merge_with_prev_subpage(struct subpage_area *start,
struct subpage_area *this,
struct subpage_area *prev)
{
BUG_ON(this == prev);
BUG_ON(this->used);
/* Can't merge used and unused regions */
if (prev->used)
return 0;
/* At the beginning. this is head, prev is tail. Can't merge. */
if (start == this)
return 0;
/* Can't merge head descriptors of page allocations. They
* are to be returned back to the page allocator on their own. */
if (this->head_of_pages)
return 0;
/* Subpage areas can be non-contiguous, if they are not a part of
* the same page(s) allocation. This usually holds if prev and this
* are fragments from the same page allocation. */
if (prev->vaddr + prev->size != (unsigned int)this)
return 0;
/* Remember that subpage_area structures are at the beginning of
* the memory areas they describe. By simply merging them with
* another area they're effectively freed. */
prev->size += this->size + sizeof(struct subpage_area);
list_del(&this->list);
return 1;
}
static int
km_merge_with_next_subpage(struct subpage_area *start,
struct subpage_area *this,
struct subpage_area *next)
{
BUG_ON(this == next);
BUG_ON(this->used);
/* At the end. this is tail, next is head. Can't merge. */
if (start == next)
return 0;
/* Can't merge used and unused regions */
if (next->used)
return 0;
/* Can't merge head descriptors of page allocations. They
* are to be returned back to the page allocator on their own. */
if (next->head_of_pages)
return 0;
/* Subpage areas can be non-contiguous, if they are not a part of
* the same head_of_page(s) allocation. This usually holds if next
* and this are fragments from the same head_of_page. */
if (this->vaddr + this->size != (unsigned int)next)
return 0;
/* Remember that subpage_area structures are at the beginning of
* the memory areas they describe. By simply merging them with
* another area they're effectively freed. */
this->size += next->size + sizeof(struct subpage_area);
list_del(&next->list);
return 1;
}
int find_and_free_subpage_area(void *vaddr, struct subpage_area **areas)
{
struct subpage_area *cur = *areas;
if (!vaddr) /* A well-known invalid address */
return -1;
if (cur->vaddr == (unsigned int)vaddr) {
struct subpage_area *prev, *next;
BUG_ON(!cur->used);
cur->used = 0;
if (!list_empty(&cur->list)) {
prev = list_entry(cur->list.prev,
struct subpage_area,
list);
if (km_merge_with_prev_subpage(*areas, cur, prev))
cur = prev;
if (!list_empty(&cur->list)) {
/* Last merge did not reduce to last
* element. */
next = list_entry(cur->list.next,
struct subpage_area,
list);
km_merge_with_next_subpage(*areas, cur, next);
}
}
km_free_empty_pages(cur, areas);
return 0;
}
list_for_each_entry(cur, &(*areas)->list, list) {
if (cur->vaddr == (unsigned int)vaddr) {
struct subpage_area *prev, *next;
BUG_ON(!cur->used);
cur->used = 0;
if (!list_empty(&cur->list)) {
prev = list_entry(cur->list.prev,
struct subpage_area,
list);
if (km_merge_with_prev_subpage(*areas,
cur, prev))
cur = prev;
if (!list_empty(&cur->list)) {
/* Last merge did not reduce to last
* element. */
next = list_entry(cur->list.next,
struct subpage_area,
list);
km_merge_with_next_subpage(*areas, cur,
next);
}
}
/* After freeing and all possible merging, try
* returning region back to page allocator. */
km_free_empty_pages(cur, areas);
return 0;
}
}
/* TODO, Return a specific error code. Here, this is a
* serious error. (Trying to free non-existing memory) */
return -1;
}
int kfree(void *vaddr)
{
int ret;
/* NOTE: If needed, lock mutex here */
ret = find_and_free_subpage_area(vaddr, &km_areas);
/* NOTE: If locked, unlock mutex here */
return ret;
}

View File

@@ -0,0 +1,31 @@
#ifndef __KMALLOC_H__
#define __KMALLOC_H__
#include <mm/alloc_page.h>
#include <l4/lib/list.h>
/*
* List member to keep track of free and unused regions in subpages.
* Smallest unit it represents is one byte, but note that it is also
* used for describing regions that span across multiple pages.
*/
struct km_area {
struct list_head list;
unsigned long vaddr;
unsigned long size;
int used;
int pg_alloc_pages; /* Means borrowed from alloc_page() */
};
extern struct list_head km_area_start;
/* Kmalloc initialisation */
void kmalloc_init(void);
/* Kmalloc allocation functions */
void *kmalloc(int size);
void *kzalloc(int size);
int kfree(void *vaddr);
#endif /* __KMALLOC_H__ */

View File

@@ -0,0 +1,28 @@
#ifndef __KMALLOC_H__
#define __KMALLOC_H__
#include <mm/alloc_page.h>
#include <l4/lib/list.h>
/* List member to keep track of free and unused regions in subpages.
* Smallest unit it represents is one byte, but note that it is also
* used for describing regions that span across multiple pages. */
struct subpage_area {
struct list_head list;
unsigned int vaddr;
unsigned int size;
unsigned int used;
unsigned int head_of_pages; /* Means head of alloc_page() */
};
extern struct subpage_area subpage_area_start;
/* Kmalloc initialisation */
void kmalloc_init(void);
/* Kmalloc allocation functions */
void *kmalloc(int size);
void *kzalloc(int size);
int kfree(void *vaddr);
#endif /* __KMALLOC_H__ */

View File

@@ -0,0 +1,202 @@
/*
* Bitmap-based linked-listable fixed-size memory cache.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <memcache/memcache.h>
#include <string.h>
#include <stdio.h>
/* Some definitions from glue/memory.h */
#define align_up(addr, size) ((((unsigned long)addr) + (size - 1)) & (~(size - 1)))
#define SZ_WORD sizeof(unsigned long)
#define WORD_BITS 32
#define BITWISE_GETWORD(x) (x >> 5) /* Divide by 32 */
#define BITWISE_GETBIT(x) (1 << (x % WORD_BITS))
static 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;
}
static 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;
}
}
/* Allocate, clear and return element */
void *mem_cache_zalloc(struct mem_cache *cache)
{
void *elem = mem_cache_alloc(cache);
memset(elem, 0, cache->struct_size);
return elem;
}
/* Allocate another element from given @cache. Returns 0 when full. */
void *mem_cache_alloc(struct mem_cache *cache)
{
int bit;
if (cache->free > 0) {
/* NOTE: If needed, must lock here */
cache->free--;
if ((bit = find_and_set_first_free_bit(cache->bitmap,
cache->total)) < 0) {
printk("Error: Anomaly in cache occupied state.\n"
"Bitmap full although cache->free > 0\n");
BUG();
}
/* NOTE: If needed, must unlock here */
return (void *)(cache->start + (cache->struct_size * bit));
} else {
/* Cache full */
return 0;
}
}
/* Free element at @addr in @cache. Return negative on error. */
int mem_cache_free(struct mem_cache *cache, void *addr)
{
unsigned int struct_addr = (unsigned int)addr;
unsigned int bit;
int err = 0;
/* Check boundary */
if (struct_addr < cache->start || struct_addr > cache->end) {
printk("Error: This address doesn't belong to this cache.\n");
return -1;
}
bit = ((struct_addr - cache->start) / cache->struct_size);
/* Check alignment:
* Find out if there was a lost remainder in last division.
* There shouldn't have been, because addresses are allocated at
* struct_size offsets from cache->start. */
if (((bit * cache->struct_size) + cache->start) != struct_addr) {
printk("Error: This address is not aligned on a predefined "
"structure address in this cache.\n");
err = -1;
return err;
}
/* NOTE: If needed, must lock here */
/* Check free/occupied state */
if (check_and_clear_bit(cache->bitmap, bit) < 0) {
printk("Error: Anomaly in cache occupied state:\n"
"Trying to free already free structure.\n");
err = -1;
goto out;
}
cache->free++;
if (cache->free > cache->total) {
printk("Error: Anomaly in cache occupied state:\n"
"More free elements than total.\n");
err = -1;
goto out;
}
out:
/* NOTE: If locked, must unlock here */
return err;
}
struct mem_cache *mem_cache_init(void *start,
int cache_size,
int struct_size,
unsigned int aligned)
{
struct mem_cache *cache = start;
unsigned int area_start;
unsigned int *bitmap;
int bwords_in_structs;
int bwords;
int total;
int bsize;
if ((struct_size < 0) || (cache_size < 0) ||
((unsigned long)start == ~(0))) {
printk("Invalid parameters.\n");
return 0;
}
/* The cache definition itself is at the beginning.
* Skipping it to get to start of free memory. i.e. the cache. */
area_start = (unsigned long)start + sizeof(struct mem_cache);
cache_size -= sizeof(struct mem_cache);
if (cache_size < struct_size) {
printk("Cache too small for given struct_size\n");
return 0;
}
/* Get how much bitmap words occupy */
total = cache_size / struct_size;
bwords = total >> 5; /* Divide by 32 */
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;
/* This should always catch too small caches */
if (total <= 0) {
printk("Cache too small for given struct_size\n");
return 0;
}
if (cache_size <= 0) {
printk("Cache too small for given struct_size\n");
return 0;
}
bitmap = (unsigned int *)area_start;
area_start = (unsigned int)(bitmap + bwords);
if (aligned) {
unsigned int addr = area_start;
unsigned int addr_aligned = align_up(area_start, struct_size);
unsigned int diff = addr_aligned - addr;
BUG_ON(diff >= struct_size);
if (diff)
total--;
cache_size -= diff;
area_start = addr_aligned;
}
INIT_LIST_HEAD(&cache->list);
cache->start = area_start;
cache->end = area_start + cache_size;
cache->total = total;
cache->free = cache->total;
cache->struct_size = struct_size;
cache->bitmap = bitmap;
/* NOTE: If needed, must initialise lock here */
memset(cache->bitmap, 0, bwords*SZ_WORD);
return cache;
}

View File

@@ -0,0 +1,50 @@
/*
* Bitmap-based link-listable fixed-size memory cache.
*
* Copyright (C) 2007 Bahadir Balban
*/
#ifndef __MEMCACHE_H__
#define __MEMCACHE_H__
#include <l4/config.h>
#include <l4/macros.h>
#include <l4/types.h>
#include <l4/lib/list.h>
/* Very basic cache structure. All it does is, keep an internal bitmap of
* items of struct_size. (Note bitmap is fairly efficient and simple for a
* fixed-size memory cache) Keeps track of free/occupied items within its
* start/end boundaries. Does not grow/shrink but you can link-list it. */
struct mem_cache {
struct list_head list;
int total;
int free;
unsigned int start;
unsigned int end;
unsigned int struct_size;
unsigned int *bitmap;
};
void *mem_cache_zalloc(struct mem_cache *cache);
void *mem_cache_alloc(struct mem_cache *cache);
int mem_cache_free(struct mem_cache *cache, void *addr);
struct mem_cache *mem_cache_init(void *start, int cache_size,
int struct_size, unsigned int alignment);
static inline int mem_cache_is_full(struct mem_cache *cache)
{
return cache->free == 0;
}
static inline int mem_cache_is_empty(struct mem_cache *cache)
{
return cache->free == cache->total;
}
static inline int mem_cache_is_last_free(struct mem_cache *cache)
{
return cache->free == 1;
}
static inline int mem_cache_total_empty(struct mem_cache *cache)
{
return cache->free;
}
#endif /* __MEMCACHE_H__ */

View File

@@ -0,0 +1,266 @@
/*
* A proof-of-concept linked-list based page allocator.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <stdio.h>
#include <string.h>
#include <l4/config.h>
#include <l4/macros.h>
#include <l4/types.h>
#include <l4/lib/list.h>
#include <l4lib/arch/syscalls.h>
#include "alloc_page.h"
#include INC_GLUE(memory.h)
#include INC_SUBARCH(mm.h)
#include INC_GLUE(memlayout.h)
struct page_allocator allocator;
static struct mem_cache *new_dcache();
/*
* Allocate a new page area from @area_sources_start. If no areas left,
* allocate a new cache first, allocate page area from the new cache.
*/
static struct page_area *new_page_area(struct page_allocator *p,
struct list_head *ccache)
{
struct mem_cache *cache;
struct page_area *new_area;
struct list_head *cache_list;
if (ccache)
cache_list = ccache;
else
cache_list = &p->dcache_list;
list_for_each_entry(cache, cache_list, list)
if ((new_area = mem_cache_alloc(cache)) != 0) {
new_area->cache = cache;
return new_area;
}
/* Must not reach here if a ccache is already used. */
BUG_ON(ccache);
if ((cache = new_dcache(p)) == 0)
return 0; /* Denotes out of memory */
new_area = mem_cache_alloc(cache);
new_area->cache = cache;
return new_area;
}
/* Given the page @quantity, finds a free region, divides and returns new area. */
static struct page_area *
get_free_page_area(int quantity, struct page_allocator *p,
struct list_head *cache_list)
{
struct page_area *new, *area;
if (quantity <= 0)
return 0;
list_for_each_entry(area, &p->page_area_list, list) {
/* Free but needs dividing */
if (area->numpages > quantity && !area->used) {
area->numpages -= quantity;
if (!(new = new_page_area(p, cache_list)))
return 0; /* No more pages */
new->pfn = area->pfn + area->numpages;
new->numpages = quantity;
new->used = 1;
INIT_LIST_HEAD(&new->list);
list_add(&new->list, &area->list);
return new;
/* Free and exact size match, no need to divide. */
} else if (area->numpages == quantity && !area->used) {
area->used = 1;
return area;
}
}
/* No more pages */
return 0;
}
void *alloc_page(int quantity)
{
struct page_area *p = get_free_page_area(quantity, &allocator, 0);
if (p)
return (void *)__pfn_to_addr(p->pfn);
else
return 0;
}
/*
* Helper to allocate a page using an internal page area cache. Returns
* a virtual address because these allocations are always internally referenced.
*/
void *alloc_page_using_cache(struct page_allocator *a, struct list_head *c)
{
struct page_area *p = get_free_page_area(1, a, c);
if (p)
return l4_map_helper((void *)__pfn_to_addr(p->pfn), 1);
else
return 0;
}
/*
* There's still free memory, but allocator ran out of page areas stored in
* dcaches. In this case, the ccache supplies a new page area, which is used to
* describe a page that stores a new dcache. If ccache is also out of page areas
* it adds the spare cache to ccache_list, uses that for the current allocation,
* and allocates a new spare cache for future use
*/
static struct mem_cache *new_dcache(struct page_allocator *p)
{
void *dpage; /* Page that keeps data cache */
void *spage; /* Page that keeps spare cache */
if((dpage = alloc_page_using_cache(p, &p->ccache_list)))
return mem_cache_init(dpage, PAGE_SIZE,
sizeof(struct page_area), 0);
/* If ccache is also full, add the spare page_area cache to ccache */
list_add(&p->spare->list, &p->ccache_list);
/* This must not fail now, and satisfy at least two page requests. */
BUG_ON(mem_cache_total_empty(p->spare) < 2);
BUG_ON(!(dpage = alloc_page_using_cache(p, &p->ccache_list)));
BUG_ON(!(spage = alloc_page_using_cache(p, &p->ccache_list)));
/* Initialise the new spare and return the new dcache. */
p->spare = mem_cache_init(spage, PAGE_SIZE, sizeof(struct page_area),0);
return mem_cache_init(dpage, PAGE_SIZE, sizeof(struct page_area), 0);
}
/*
* Only to be used at initialisation. Allocates memory caches that contain
* page_area elements by incrementing the free physical memory mark by
* PAGE_SIZE.
*/
static struct mem_cache *new_allocator_startup_cache(unsigned long *start)
{
struct page_area *area;
struct mem_cache *cache;
cache = mem_cache_init(l4_map_helper((void *)*start, 1), PAGE_SIZE,
sizeof(struct page_area), 0);
area = mem_cache_alloc(cache);
/* Initialising the dummy just for illustration */
area->pfn = __pfn(*start);
area->numpages = 1;
area->cache = cache;
INIT_LIST_HEAD(&area->list);
/* FIXME: Should I add this to the page area list? */
*start += PAGE_SIZE;
return cache;
}
/*
* All physical memory is tracked by a simple linked list implementation. A
* single list contains both used and free page_area descriptors. Each page_area
* describes a continuous region of physical pages, indicating its location by
* it's pfn.
*
* alloc_page() keeps track of all page-granuled memory, except the bits that
* were in use before the allocator initialised. This covers anything that is
* outside the @start @end range. This includes the page tables, first caches
* allocated by this function, compile-time allocated kernel data and text.
* Also other memory regions like IO are not tracked by alloc_page() but by
* other means.
*/
void init_page_allocator(unsigned long start, unsigned long end)
{
struct page_area *freemem;
struct mem_cache *dcache, *ccache;
INIT_LIST_HEAD(&allocator.dcache_list);
INIT_LIST_HEAD(&allocator.ccache_list);
INIT_LIST_HEAD(&allocator.page_area_list);
/* Primary cache list that stores page areas of regular data. */
dcache = new_allocator_startup_cache(&start);
list_add(&dcache->list, &allocator.dcache_list);
/* The secondary cache list that stores page areas of caches */
ccache = new_allocator_startup_cache(&start);
list_add(&ccache->list, &allocator.ccache_list);
/* Initialise first area that describes all of free physical memory */
freemem = mem_cache_alloc(dcache);
INIT_LIST_HEAD(&freemem->list);
freemem->pfn = __pfn(start);
freemem->numpages = __pfn(end) - freemem->pfn;
freemem->cache = dcache;
freemem->used = 0;
/* Add it as the first unused page area */
list_add(&freemem->list, &allocator.page_area_list);
/* Allocate and add the spare page area cache */
allocator.spare = mem_cache_init(l4_map_helper(alloc_page(1), 1),
PAGE_SIZE, sizeof(struct page_area),
0);
}
/* Merges two page areas, frees area cache if empty, returns the merged area. */
struct page_area *merge_free_areas(struct page_area *before,
struct page_area *after)
{
struct mem_cache *c;
BUG_ON(before->pfn + before->numpages != after->pfn);
BUG_ON(before->used || after->used)
BUG_ON(before == after);
before->numpages += after->numpages;
list_del(&after->list);
c = after->cache;
mem_cache_free(c, after);
/* Recursively free the cache page */
if (mem_cache_is_empty(c))
BUG_ON(free_page(l4_unmap_helper(c, 1)) < 0)
return before;
}
static int find_and_free_page_area(void *addr, struct page_allocator *p)
{
struct page_area *area, *prev, *next;
/* First find the page area to be freed. */
list_for_each_entry(area, &p->dcache_list, list)
if (__pfn_to_addr(area->pfn) == (unsigned long)addr &&
area->used) { /* Found it */
area->used = 0;
goto found;
}
return -1; /* Finished the loop, but area not found. */
found:
/* Now merge with adjacent areas, if possible */
if (area->list.prev != &p->dcache_list) {
prev = list_entry(area->list.prev, struct page_area, list);
if (!prev->used)
area = merge_free_areas(prev, area);
}
if (area->list.next != &p->dcache_list) {
next = list_entry(area->list.next, struct page_area, list);
if (!next->used)
area = merge_free_areas(area, next);
}
return 0;
}
int free_page(void *paddr)
{
return find_and_free_page_area(paddr, &allocator);
}

View File

@@ -0,0 +1,36 @@
#ifndef __ALLOC_PAGE_H__
#define __ALLOC_PAGE_H__
#include <memcache/memcache.h>
/* List member to keep track of free and unused physical pages.
* Has PAGE_SIZE granularity */
struct page_area {
struct list_head list;
unsigned int used; /* Used or free */
unsigned int pfn; /* Base pfn */
unsigned int numpages; /* Number of pages this region covers */
struct mem_cache *cache;/* The cache used when freeing the page area for
* quickly finding where the area is stored. */
};
struct page_allocator {
/* Keep track of page area lists and allocated caches for page areas. */
struct list_head page_area_list;
/* Caches of page areas that refer to any kind of data */
struct list_head dcache_list;
/* Caches of page areas that refer to cache pages */
struct list_head ccache_list;
/* A spare cache to aid when both caches are full */
struct mem_cache *spare;
};
/* Initialises the page allocator */
void init_page_allocator(unsigned long start, unsigned long end);
/* Page allocation functions */
void *alloc_page(int quantity);
void *zalloc_page(int quantity);
int free_page(void *paddr);
#endif /* __ALLOC_PAGE_H__ */

110
tasks/libmem/run_tests.py Executable file
View File

@@ -0,0 +1,110 @@
#!/usr/bin/python
import os
import shutil
from os.path import join
import sys
project_root = join(os.getcwd(), "../..")
source_root = os.path.join(project_root, 'src')
headers_root = os.path.join(project_root, 'include')
tests_run_root = os.path.join(os.getcwd(), 'tmp')
tools_root = os.getcwd()
init_state = "page_init.out"
exit_state = "page_exit.out"
SZ_10MB = 1024 * 1024 * 10
def power(x, y):
res = 1
for i in range(y):
res = res * x;
return res
def test_mm():
'''
Tries to set up meaningful input parameters for page_size, maximum allocation
size, total number of allocations, and total pages, and tests the memory allocator
in every one of these combinations. The parameter guessing is not great, but at least
some test cases are reasonable.
'''
page_sizes = [128, 256, 512, 1024, 2048, 4096, 8192]
max_alloc_sizes = [1, 10, 40, 50, 100, 200]
for page_size in page_sizes:
numpages = SZ_10MB / page_size
for i in range(1, 3):
res = numpages / power(10, i) # Divide numpages to 10, 100, 1000
if res > 0:
max_alloc_sizes.append(numpages/10)
max_alloc_sizes.append(numpages/100)
max_alloc_sizes.append(numpages/1000)
for max_alloc_size in max_alloc_sizes:
if max_alloc_size >= numpages: # If a single allocation exceeds total, adjust.
max_alloc_size = numpages / 2
num_allocs = numpages / (max_alloc_size) * 2 * 2 / 3
cmd = "./test -a=p -n=%d -s=%d -fi=%s -fx=%s -ps=%d -pn=%d" % \
(num_allocs, max_alloc_size, join(tests_run_root, init_state),\
join(tests_run_root, exit_state), page_size, numpages)
print "num_allocs = %d, max_alloc_size = %d, page_size = %d, numpages = %d" % \
(num_allocs, max_alloc_size, page_size, numpages)
os.system(cmd)
#os.system("cat %s" % join(tests_run_root, init_state))
diffcmd = "diff " + join(tests_run_root, init_state) + " " + join(tests_run_root, exit_state)
if os.system(diffcmd) != 0:
print "Error: %s has failed.\n" % cmd
sys.exit(1)
def test_km():
'''
Tries to set up meaningful input parameters for payload size, maximum allocation
size, total number of allocations, and total pages, and tests kmalloc
in every one of these combinations. The parameter guessing is not great, but at least
some test cases are reasonable.
'''
page_sizes = [4096, 8192]
max_alloc_sizes = [1, 10, 40, 50, 100, 200, 1024, 2048, 4096, 10000, 50000, 100000]
numpages = 1024
for page_size in page_sizes:
for max_alloc_size in max_alloc_sizes:
num_allocs = (numpages * page_size * 3) / (max_alloc_size * 2)
cmd = "./test -a=k -n=%d -s=%d -fi=%s -fx=%s -ps=%d -pn=%d" % \
(num_allocs, max_alloc_size, join(tests_run_root, init_state),\
join(tests_run_root, exit_state), page_size, numpages)
print "num_allocs = %d, max_alloc_size = %d, page_size = %d, numpages = %d" %\
(num_allocs, max_alloc_size, page_size, numpages)
diffcmd = "diff " + join(tests_run_root, init_state) + " " +\
join(tests_run_root, exit_state)
if os.system(diffcmd) != 0:
print "Error: %s has failed.\n" % cmd
sys.exit(1)
def test_mm_params(num_allocs, max_alloc_size, page_size, numpages, iterations):
for i in range(iterations):
cmd = "./test -a=p -n=%d -s=%d -fi=%s -fx=%s -ps=%d -pn=%d" % \
(num_allocs, max_alloc_size, join(tests_run_root, init_state),\
join(tests_run_root, exit_state), page_size, numpages)
print "num_allocs = %d, max_alloc_size = %d, page_size = %d, numpages = %d" % \
(num_allocs, max_alloc_size, page_size, numpages)
os.system(cmd)
#os.system("cat %s" % join(tests_run_root, init_state))
diffcmd = "diff " + join(tests_run_root, init_state) + " " + join(tests_run_root, exit_state)
if os.system(diffcmd) != 0:
print "Error: %s has failed.\n" % cmd
sys.exit(1)
def run_tests():
if os.path.exists(tests_run_root):
shutil.rmtree(tests_run_root)
os.mkdir(tests_run_root)
# for i in range (100):
#test_km()
test_mm()
#test_mm_params(10922, 10, 128, 81920, 50)
#test_km()
#test_mc()
if __name__ == '__main__':
run_tests()

View File

@@ -0,0 +1,9 @@
# Inherit global environment
Import('env')
# The set of source files associated with this SConscript file.
src_local = ['main.c', 'test_kmalloc.c', 'test_memcache.c', 'test_allocpage.c', 'test_alloc_generic.c', 'debug.c', 'memory.c', 'clz.c']
obj = env.Object(src_local)
Return('obj')

16
tasks/libmem/tests/clz.c Normal file
View File

@@ -0,0 +1,16 @@
#include <l4/macros.h>
#include <l4/types.h>
#include <l4/config.h>
/* Emulation of 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;
}

7
tasks/libmem/tests/clz.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef __CLZ_H__
#define __CLZ_H__
unsigned int __clz(unsigned int bitvector);
#endif /* __CLZ_H__ */

View File

@@ -0,0 +1,33 @@
#include "debug.h"
#include <stdio.h>
void print_page_area_list(struct page_allocator *p)
{
struct page_area *area;
list_for_each_entry (area, &p->page_area_list, list) {
printf("%-20s\n%-20s\n", "Page area:","-------------------------");
printf("%-20s %u\n", "Pfn:", area->pfn);
printf("%-20s %d\n", "Used:", area->used);
printf("%-20s %d\n\n", "Number of pages:", area->numpages);
}
}
void print_km_area(struct km_area *s)
{
printf("%-20s\n%-20s\n", "Subpage area:","-------------------------");
printf("%-20s 0x%lu\n", "Addr:", s->vaddr);
printf("%-20s 0x%lu\n", "Size:", s->size);
printf("%-20s %d\n", "Used:", s->used);
printf("%-20s %d\n\n", "Head_of_pages:", s->pg_alloc_pages);
}
void print_km_area_list(struct list_head *km_areas)
{
struct km_area *area;
list_for_each_entry (area, km_areas, list)
print_km_area(area);
}

View File

@@ -0,0 +1,17 @@
#ifndef __DEBUG_H__
#define __DEBUG_H__
#include <kmalloc/kmalloc.h>
#include <mm/alloc_page.h>
#include <l4/lib/list.h>
#if defined(DEBUG)
#define dprintf printf
#else
#define dprintf(...)
#endif
void print_page_area_list(struct page_allocator *p);
void print_km_area_list(struct list_head *s);
void print_km_area(struct km_area *s);
#endif /* DEBUG_H */

View File

@@ -0,0 +1,28 @@
#include "libl4.h"
unsigned long virt_to_phys(unsigned long addr)
{
return addr;
}
unsigned long phys_to_virt(unsigned long addr)
{
return addr;
}
u32 l4_getpid(unsigned int *a, unsigned int *b, unsigned int *c)
{
return 0;
}
u32 l4_unmap(unsigned long a, unsigned long b, u32 npages)
{
return 0;
}
u32 l4_map(unsigned long a, unsigned long b, u32 size, u32 flags, unsigned int tid)
{
return 0;
}

View File

@@ -0,0 +1,17 @@
/*
* Mock-up l4 library definitions for host testing.
*
*/
#ifndef __TESTS_LIBL4_H__
#define __TESTS_LIBL4_H__
#include <l4/macros.h>
#include <l4/config.h>
#include <l4/types.h>
u32 l4_map(unsigned long phys, unsigned long virt, u32 size, u32 flags, u32 tid);
u32 l4_unmap(unsigned long a, unsigned long b, u32 npages);
u32 l4_getpid(unsigned int *a, unsigned int *b, unsigned int *c);
#endif

View File

250
tasks/libmem/tests/main.c Normal file
View File

@@ -0,0 +1,250 @@
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <l4/macros.h>
#include <l4/config.h>
#include <kmalloc/kmalloc.h>
#include <mm/alloc_page.h>
#include INC_SUBARCH(mm.h)
#include INC_ARCH(linker.h)
#include INC_PLAT(printascii.h)
#include INC_PLAT(offsets.h)
#include INC_GLUE(memlayout.h)
#include "tests.h"
#include "test_kmalloc.h"
#include "test_allocpage.h"
#include "test_memcache.h"
#include "clz.h"
#include "memory.h"
#include "libl4.h"
#include "debug.h"
unsigned int TEST_PHYSMEM_TOTAL_PAGES = 250;
unsigned int TEST_PHYSMEM_TOTAL_SIZE;
unsigned int PHYS_MEM_START;
unsigned int PHYS_MEM_END;
void *malloced_test_memory;
void memory_initialise(void)
{
init_page_allocator(PHYS_MEM_START, PHYS_MEM_END);
kmalloc_init();
}
/* Allocating memory from the host C library, and
* it is used as if it is the physical memory available
* on the system.
*/
void alloc_test_memory()
{
TEST_PHYSMEM_TOTAL_SIZE = (PAGE_SIZE * TEST_PHYSMEM_TOTAL_PAGES);
if (!(malloced_test_memory = malloc(TEST_PHYSMEM_TOTAL_SIZE)))
printf("Host system out of memory.\n");
PHYS_MEM_START = (unsigned int)malloced_test_memory;
PHYS_MEM_END = PHYS_MEM_START + TEST_PHYSMEM_TOTAL_SIZE;
PHYS_MEM_START = page_align_up(PHYS_MEM_START);
PHYS_MEM_END = page_align(PHYS_MEM_END);
/* Normally _end is to know where the loaded kernel image
* ends in physical memory, so the system can start allocating
* physical memory from there. Because in our mock-up there's no
* used space in the malloc()'ed memory, _end is the same as the
* beginning of malloc()'ed memory.
*/
_end = PHYS_MEM_START;
dprintf("Initialising physical memory\n");
dprintf("Initialising allocators:\n");
memory_initialise();
}
struct cmdline_opts {
char run_allocator;
int allocations;
int alloc_size_max;
int physmem_pages;
int page_size;
int no_of_pages;
char *finit_path;
char *fexit_path;
} options;
int check_options_validity(struct cmdline_opts *opts)
{
if (opts->allocations <= 0) {
printf("Invalid number of allocations: %d\n", opts->allocations);
return -1;
}
if (opts->no_of_pages <= 0) {
printf("Invalid number of pages: %d\n", opts->no_of_pages);
return -1;
}
if (opts->alloc_size_max <= 0) {
printf("Invalid alloc_size_max: %d\n", opts->alloc_size_max);
return -1;
}
if (opts->page_size <= 0) {
printf("Invalid page_size: %d\n", opts->page_size);
return -1;
}
return 0;
}
void print_options(struct cmdline_opts *opts)
{
dprintf("Running: %s\n",
((opts->run_allocator == 'p') ? "page allocator" :
((opts->run_allocator == 'k') ? "kmalloc/kfree" :
"memcache allocator")));
dprintf("Total allocations: %d\n", opts->allocations);
dprintf("Maximum allocation size: %d, 0x%x(hex)\n\n",
opts->alloc_size_max, opts->alloc_size_max);
dprintf("Initial state file: %s\n", opts->finit_path);
dprintf("Exit state file: %s\n", opts->fexit_path);
}
void display_help(void)
{
printf("Main:\n");
printf("\tUsage:\n");
printf("\tmain\t-a=<p>|<k>|<m> [-n=<number of allocations>] [-s=<maximum size for any allocation>]\n"
"\t\t[-fi=<file to dump init state>] [-fx=<file to dump exit state>]\n"
"\t\t[-ps=<page size>] [-pn=<total number of pages>]\n");
printf("\n");
}
int get_cmdline_opts(int argc, char *argv[], struct cmdline_opts *opts)
{
int parsed = 0;
memset(opts, 0, sizeof (struct cmdline_opts));
if (argc <= 1)
return -1;
for (int i = 1; i < argc; i++) {
if (argv[i][0] == '-' && argv[i][2] == '=') {
if (argv[i][1] == 'a') {
if (argv[i][3] == 'k' ||
argv[i][3] == 'm' ||
argv[i][3] == 'p') {
opts->run_allocator = argv[i][3];
parsed = 1;
}
}
if (argv[i][1] == 'n') {
opts->allocations = atoi(&argv[i][3]);
parsed = 1;
}
if (argv[i][1] == 's') {
opts->alloc_size_max = atoi(&argv[i][3]);
parsed = 1;
}
}
if (argv[i][0] == '-' && argv[i][1] == 'f'
&& argv[i][3] == '=') {
if (argv[i][2] == 'i') {
opts->finit_path = &argv[i][4];
parsed = 1;
}
if (argv[i][2] == 'x') {
opts->fexit_path = &argv[i][4];
parsed = 1;
}
}
if (argv[i][0] == '-' && argv[i][1] == 'p'
&& argv[i][3] == '=') {
if (argv[i][2] == 's') {
opts->page_size = atoi(&argv[i][4]);
parsed = 1;
}
if (argv[i][2] == 'n') {
opts->no_of_pages = atoi(&argv[i][4]);
parsed = 1;
}
}
}
if (!parsed)
return -1;
return 0;
}
void get_output_files(FILE **out1, FILE **out2,
char *alloc_func_name, char *rootpath)
{
char pathbuf[150];
char *root = "/tmp/";
char *initstate_prefix = "test_initstate_";
char *endstate_prefix = "test_endstate_";
char *extension = ".out";
if (!rootpath)
rootpath = root;
/* File path manipulations */
sprintf(pathbuf, "%s%s%s%s", rootpath, initstate_prefix, alloc_func_name, extension);
*out1 = fopen(pathbuf,"w+");
sprintf(pathbuf, "%s%s%s%s", rootpath, endstate_prefix, alloc_func_name, extension);
*out2 = fopen(pathbuf, "w+");
return;
}
int main(int argc, char *argv[])
{
FILE *finit, *fexit;
int output_files = 0;
if (get_cmdline_opts(argc, argv, &options) < 0) {
display_help();
return 1;
}
print_options(&options);
if (check_options_validity(&options) < 0)
exit(1);
if (options.finit_path && options.fexit_path) {
finit = fopen(options.finit_path, "w+");
fexit = fopen(options.fexit_path, "w+");
output_files = 1;
}
if (options.page_size) {
PAGE_SIZE = options.page_size;
PAGE_MASK = PAGE_SIZE - 1;
PAGE_BITS = 32 - __clz(PAGE_MASK);
dprintf("Using: Page Size: %d\n", PAGE_SIZE);
dprintf("Using: Page Mask: 0x%x\n", PAGE_MASK);
dprintf("Using: Page Bits: %d\n", PAGE_BITS);
}
if (options.no_of_pages) {
dprintf("Using: Total pages: %d\n", options.no_of_pages);
TEST_PHYSMEM_TOTAL_PAGES = options.no_of_pages;
}
alloc_test_memory();
if (options.run_allocator == 'p') {
if (!output_files)
get_output_files(&finit, &fexit, "alloc_page", 0);
test_allocpage(options.allocations, options.alloc_size_max,
finit, fexit);
} else if (options.run_allocator == 'k') {
if (!output_files)
get_output_files(&finit, &fexit, "kmalloc", 0);
test_kmalloc(options.allocations, options.alloc_size_max,
finit, fexit);
} else if (options.run_allocator == 'm') {
if (!output_files)
get_output_files(&finit, &fexit, "memcache", 0);
test_memcache(options.allocations, options.alloc_size_max,
finit, fexit, 1);
} else {
printf("Invalid allocator option.\n");
}
free((void *)malloced_test_memory);
fclose(finit);
fclose(fexit);
return 0;
}

View File

@@ -0,0 +1,9 @@
#include <l4/macros.h>
#include <l4/config.h>
#include <l4/types.h>
#include INC_GLUE(memory.h)
unsigned int PAGE_SIZE = TEST_PAGE_SIZE;
unsigned int PAGE_MASK = TEST_PAGE_MASK;
unsigned int PAGE_BITS = TEST_PAGE_BITS;

View File

@@ -0,0 +1,216 @@
/*
* Generic random allocation/deallocation test
*
* Copyright 2007 (C) Bahadir Balban
*
*/
#include <l4/macros.h>
#include <l4/config.h>
#include <l4/types.h>
#include INC_GLUE(memory.h)
#include <l4/lib/list.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "test_alloc_generic.h"
#include "debug.h"
void print_test_state(unsigned int title,
print_alloc_state_t print_allocator_state)
{
switch (title) {
case TEST_STATE_BEGIN:
printf("=================\n"
"===== BEGIN =====\n"
"=================\n\n");
break;
case TEST_STATE_MIDDLE:
printf("==================\n"
"===== MIDDLE =====\n"
"==================\n\n");
break;
case TEST_STATE_END:
printf("===========\n"
"=== END ===\n"
"===========\n\n");
break;
case TEST_STATE_ERROR:
printf("=================\n"
"===== ERROR =====\n"
"=================\n\n");
break;
default:
printf("Title error.\n");
}
print_allocator_state();
}
void get_output_filepaths(FILE **out1, FILE **out2,
char *alloc_func_name)
{
char pathbuf[150];
char *rootpath = "/tmp/";
char *initstate_prefix = "test_initstate_";
char *endstate_prefix = "test_endstate_";
char *extention = ".out";
/* File path manipulations */
sprintf(pathbuf, "%s%s%s%s", rootpath, initstate_prefix, alloc_func_name, extention);
*out1 = fopen(pathbuf,"w+");
sprintf(pathbuf, "%s%s%s%s", rootpath, endstate_prefix, alloc_func_name, extention);
*out2 = fopen(pathbuf, "w+");
return;
}
/* This function is at the heart of generic random allocation testing.
* It is made as simple as possible, and can be used for testing all
* allocators. It randomly allocates/deallocates data and prints out
* the outcome of the action. Here are a few things it does and doesn't
* do:
* - It does not test false input on the allocators, e.g. attempting
* to free an address that hasn't been allocated, or attempting to
* free address 0.
* - It does capture and compare initial and final states of the
* allocators' internal structures after all allocations are freed.
* This is done by comparing two files filled with allocator state
* by functions supplied by the allocators themselves.
* - It expects the allocator NOT to run out of memory.
*/
int
test_alloc_free_random_order(const int MAX_ALLOCATIONS,
const int ALLOC_SIZE_MAX,
alloc_func_t alloc,
free_func_t free,
print_alloc_state_t print_allocator_state,
FILE *state_init_file, FILE *state_end_file)
{
/* The last element in full_state that tells about any full index.
* This is the limit the random deallocation would use to find a full
* index */
int random_size;
int random_action;
int random_index;
int alloc_so_far = 0;
int full_state_last = -1;
int halfway_through = 0;
FILE * const default_stdout = stdout;
/* Memory pointers */
void *mem[MAX_ALLOCATIONS];
/* Each element keeps track of one currently full index number */
int full_state[MAX_ALLOCATIONS];
/* Check arguments first */
if (!MAX_ALLOCATIONS || !ALLOC_SIZE_MAX || !alloc || !free
|| !print_allocator_state || !state_init_file || !state_end_file) {
printf("Invalid arguments to %s()\n", __FUNCTION__);
return 1;
}
memset(mem, 0, MAX_ALLOCATIONS * sizeof(void *));
memset(full_state, 0, MAX_ALLOCATIONS * sizeof(int));
//print_test_state(TEST_STATE_BEGIN, print_allocator_state);
stdout = state_init_file;
print_test_state(TEST_STATE_BEGIN, print_allocator_state);
stdout = default_stdout;
/* Randomly either allocate/deallocate at a random
* index, of random size */
srand(time(0));
while (1) {
if (alloc_so_far < (MAX_ALLOCATIONS / 2)) {
/* Give more chance to allocations at the beginning */
if ((rand() % 4) == 0) /* 1/4 chance */
random_action = FREE;
else /* 3/4 chance */
random_action = ALLOCATE;
} else {
if (!halfway_through) {
#if defined (DEBUG)
print_test_state(TEST_STATE_MIDDLE,
print_allocator_state);
#endif
halfway_through = 1;
}
/* Give more chane to freeing after halfway-through */
if ((rand() % 3) == 0) /* 1/3 chance */
random_action = ALLOCATE;
else /* 2/3 chance */
random_action = FREE;
}
random_size = (rand() % (ALLOC_SIZE_MAX-1)) + 1;
if (random_action == ALLOCATE) {
if (alloc_so_far < MAX_ALLOCATIONS) {
alloc_so_far++;
for (int i = 0; i < MAX_ALLOCATIONS; i++) {
if (mem[i] == 0) { // Find the first empty slot.
int allocation_error =
((mem[i] = alloc(random_size)) <= 0);
dprintf("%-12s%-8s%-12p%-8s%-10d\n",
"alloc:", "addr:", mem[i],
"size:", random_size);
if (allocation_error) {
print_test_state(TEST_STATE_ERROR,
print_allocator_state);
if (mem[i] < 0) {
printf("Error: alloc() returned negative value\n");
BUG();
} else if (mem[i] == 0) {
printf("Error: Allocator is out of memory.\n");
return 1;
}
}
full_state_last++;
full_state[full_state_last] = i;
break;
}
}
} else
random_action = FREE;
}
if (random_action == FREE) {
/* all are free, can't free anymore */
if (full_state_last < 0)
continue;
else if (full_state_last > 0)
random_index = rand() % full_state_last;
else
random_index = 0; /* Last item */
if(mem[full_state[random_index]] == 0)
BUG();
if (free(mem[full_state[random_index]]) < 0)
BUG();
dprintf("%-12s%-8s%-12p\n","free:",
"addr:", mem[full_state[random_index]]);
mem[full_state[random_index]] = 0;
/* Fill in the empty gap with last element */
full_state[random_index] = full_state[full_state_last];
/* Last element now in the gap
* (somewhere inbetween first and last) */
full_state[full_state_last] = 0;
/* One less in the number of full items */
full_state_last--;
}
/* Check that all allocations and deallocations took place */
if (alloc_so_far == MAX_ALLOCATIONS && full_state_last < 0) {
for (int i = 0; i < MAX_ALLOCATIONS; i++)
BUG_ON(full_state[i] != 0); // A final sanity check.
break;
}
}
//print_test_state(TEST_STATE_END, print_allocator_state);
stdout = state_end_file;
print_test_state(TEST_STATE_BEGIN, print_allocator_state);
stdout = default_stdout;
return 0;
}

View File

@@ -0,0 +1,29 @@
#ifndef __TEST_ALLOC_GENERIC_H__
#define __TEST_ALLOC_GENERIC_H__
enum test_state_title {
TEST_STATE_BEGIN = 0,
TEST_STATE_MIDDLE,
TEST_STATE_END,
TEST_STATE_ERROR
};
typedef void (*print_alloc_state_t)(void);
typedef void *(*alloc_func_t)(int size);
typedef int (*free_func_t)(void *addr);
enum alloc_action {
FREE = 0,
ALLOCATE = 1,
};
void get_output_filepaths(FILE **out1, FILE **out2,
char *alloc_func_name);
int test_alloc_free_random_order(const int MAX_ALLOCATIONS,
const int ALLOC_SIZE_MAX,
alloc_func_t alloc, free_func_t free,
print_alloc_state_t print_allocator_state,
FILE *init_state, FILE *exit_state);
#endif /* __TEST_ALLOC_GENERIC_H__ */

View File

@@ -0,0 +1,85 @@
/*
* Testing code for the page allocator.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/macros.h>
#include <l4/config.h>
#include <l4/types.h>
#include <l4/lib/list.h>
#include INC_GLUE(memory.h)
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "test_allocpage.h"
#include "test_alloc_generic.h"
#include "debug.h"
unsigned int PAGE_ALLOCATIONS = 30;
unsigned int PAGE_ALLOC_SIZE_MAX = 8;
extern struct page_allocator allocator;
void print_page_area(struct page_area *a, int areano)
{
printf("Area starts @: 0x%lu, %s, numpages: %d\n",
__pfn_to_addr(a->pfn),
(a->used) ? "used" : "unused", a->numpages);
return;
}
void print_areas(struct list_head *area_head)
{
struct page_area *cur;
int areano = 1;
printf("Page areas:\n-------------\n");
list_for_each_entry(cur, area_head, list)
print_page_area(cur, areano++);
}
void print_cache(struct mem_cache *c, int cacheno)
{
printf("Cache %d state:\n-------------\n", cacheno);
printf("Total: %d\n", c->total);
printf("Free: %d\n", c->free);
printf("Start: 0x%x\n", c->start);
}
void print_caches(struct list_head *cache_head)
{
int caches = 1;
struct mem_cache *cur;
list_for_each_entry(cur, cache_head, list)
print_cache(cur, caches++);
}
void print_page_allocator_state(void)
{
print_areas(&allocator.page_area_list);
printf("Data Cache:\n--------\n");
print_caches(&allocator.dcache_list);
printf("Cache Cache:\n----------\n");
print_caches(&allocator.ccache_list);
}
/* FIXME: with current default parameters (allocations = 30, sizemax = 8),
* for some odd reason, we got the bug at line 280 in alloc_page.c.
* Very weird. Find out why.
*/
void test_allocpage(int page_allocations, int page_alloc_size_max,
FILE *init_state, FILE *exit_state)
{
//if (!page_allocations)
// page_allocations = PAGE_ALLOCATIONS;
//if (!page_alloc_size_max)
// page_alloc_size_max = PAGE_ALLOC_SIZE_MAX;
dprintf("\nPAGE ALLOCATOR TEST:====================================\n\n");
test_alloc_free_random_order(page_allocations, page_alloc_size_max,
alloc_page, free_page,
print_page_allocator_state,
init_state, exit_state);
}

View File

@@ -0,0 +1,13 @@
#ifndef __TEST_ALLOCPAGE_H__
#define __TEST_ALLOCPAGE_H__
#include <mm/alloc_page.h>
#include "tests.h"
void test_allocpage(int num_allocs, int alloc_max, FILE *init, FILE *exit);
void print_page_area(struct page_area *a, int no);
void print_caches(struct list_head *cache_head);
void print_cache(struct mem_cache *c, int cacheno);
void print_areas(struct list_head *area_head);
void print_page_area(struct page_area *ar, int areano);
#endif

View File

@@ -0,0 +1,42 @@
/*
* Testing code for the kmalloc allocator.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/macros.h>
#include <l4/config.h>
#include <l4/types.h>
#include <l4/lib/list.h>
#include INC_GLUE(memory.h)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "test_alloc_generic.h"
#include "test_allocpage.h"
#include "debug.h"
#include "tests.h"
extern struct list_head km_area_start;
void print_kmalloc_state(void)
{
print_km_area_list(&km_area_start);
}
void test_kmalloc(int kmalloc_allocations, int kmalloc_alloc_size_max,
FILE *init_state, FILE *exit_state)
{
unsigned int KMALLOC_ALLOCATIONS = 20;
unsigned int KMALLOC_ALLOC_SIZE_MAX = (PAGE_SIZE * 3);
if (!kmalloc_allocations)
kmalloc_allocations = KMALLOC_ALLOCATIONS;
if (!kmalloc_alloc_size_max)
kmalloc_alloc_size_max = KMALLOC_ALLOC_SIZE_MAX;
test_alloc_free_random_order(kmalloc_allocations, kmalloc_alloc_size_max,
kmalloc, kfree, print_kmalloc_state,
init_state, exit_state);
}

View File

@@ -0,0 +1,8 @@
#ifndef __TEST_KMALLOC_H__
#define __TEST_KMALLOC_H__
#include <kmalloc/kmalloc.h>
void test_kmalloc(int num_allocs, int allocs_max, FILE *initstate, FILE *exitstate);
#endif

View File

@@ -0,0 +1,115 @@
/*
* Testing code for the memcache structure.
*
* Copyright (C) 2007 Bahadir Balban
*/
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memcache/memcache.h>
#include "test_memcache.h"
#include "test_alloc_generic.h"
#include "debug.h"
#include "tests.h"
#include <l4/macros.h>
#include <l4/config.h>
#include <l4/types.h>
#include <l4/lib/list.h>
#include INC_GLUE(memory.h)
unsigned int MEM_CACHE_SIZE;
struct mem_cache *this;
void *buffer;
void *mem_cache_alloc_wrapped(int size)
{
return mem_cache_alloc(this);
}
int mem_cache_free_wrapped(void *addr)
{
return mem_cache_free(this, addr);
}
void print_memcache_state(void)
{
printf("%-15s%d\n","Total:", this->total);
printf("%-15s%d\n","Free:", this->free);
printf("Bitmap has %d words:\n", BITWISE_GETWORD(this->total) + 1);
for (int i = 0; i <= BITWISE_GETWORD(this->total); i++)
printf("0x%x\n", this->bitmap[i]);
}
int test_memcache_init_aligned(int *items_max, int item_size)
{
if (item_size * 10 > MEM_CACHE_SIZE)
MEM_CACHE_SIZE = item_size * 10;
if (!(buffer = calloc(1, MEM_CACHE_SIZE))) {
printf("System out of memory.\n");
BUG();
}
if ((this = mem_cache_init(buffer, MEM_CACHE_SIZE,
item_size, 1)) == 0) {
printf("Unable to initialise cache.\n");
return -1;
}
*items_max = mem_cache_total_empty(this);
printf("\nMEMCACHE TEST: ALIGNED ELEMENTS\n==========================\n");
printf("%-30s%d\n", "Item size:", item_size);
printf("%-30s0x%x\n", "Cache occupied space:", MEM_CACHE_SIZE);
printf("%-30s%d\n","Total items in cache:", *items_max);
printf("%-30s0x%x\n","Total items space:", (*items_max * item_size));
return 0;
}
int test_memcache_init(int *items_max, int item_size)
{
if (item_size * 10 > MEM_CACHE_SIZE)
MEM_CACHE_SIZE = item_size * 10;
printf("%s: Allocating cache memory.\n",__FUNCTION__);
if (!(buffer = calloc(1, MEM_CACHE_SIZE))) {
printf("System out of memory.\n");
BUG();
}
if ((this = mem_cache_init(buffer, MEM_CACHE_SIZE,
item_size, 0)) == 0) {
printf("Unable to initialise cache.\n");
return -1;
}
*items_max = mem_cache_total_empty(this);
printf("\nMEMCACHE TEST:\n========================\n");
printf("%-30s%d\n", "Item size:", item_size);
printf("%-30s0x%x\n", "Cache occupied space:", MEM_CACHE_SIZE);
printf("%-30s%d\n","Total items in cache:", *items_max);
printf("%-30s0x%x\n","Total items space:", (*items_max * item_size));
return 0;
}
int test_memcache(int items_max, int item_size, FILE *init_state, FILE *exit_state, int aligned)
{
const unsigned int TEST_CACHE_ITEM_SIZE = 5;
MEM_CACHE_SIZE = PAGE_SIZE * 5;
if (!item_size)
item_size = TEST_CACHE_ITEM_SIZE;
/* items_max value is ignored and overwritten because caches have fixed size. */
test_memcache_init(&items_max, item_size);
test_alloc_free_random_order(items_max, /* unused */ 2, mem_cache_alloc_wrapped,
mem_cache_free_wrapped, print_memcache_state,
init_state, exit_state);
free(buffer);
if (aligned) {
test_memcache_init_aligned(&items_max, item_size);
test_alloc_free_random_order(items_max, /* unused */ 2, mem_cache_alloc_wrapped,
mem_cache_free_wrapped, print_memcache_state,
init_state, exit_state);
}
free(buffer);
return 0;
}

View File

@@ -0,0 +1,10 @@
#ifndef __TEST_MEMCACHE_H__
#define __TEST_MEMCACHE_H__
#include <memcache/memcache.h>
int test_memcache(int num_alloc, int alloc_size_max, FILE *initstate, FILE *exitstate, int aligned);
#endif /* __TEST_MEMCACHE_H__ */

View File

@@ -0,0 +1,21 @@
#ifndef __TESTS_H__
#define __TESTS_H__
/* Mock-up physical memory */
extern unsigned int TEST_PHYSMEM_TOTAL_PAGES;
extern unsigned int TEST_PHYSMEM_TOTAL_SIZE;
/* Allocator test */
extern unsigned int PAGE_ALLOCATIONS;
extern unsigned int PAGE_ALLOC_SIZE_MAX;
/* Memcache test */
extern unsigned int MEMCACHE_ALLOCS_MAX;
extern unsigned int TEST_CACHE_ITEM_SIZE;
/* Kmalloc */
extern unsigned int KMALLOC_ALLOCATIONS;
extern unsigned int KMALLOC_ALLOC_SIZE_MAX;
#endif /* __TESTS_H__ */

30
tasks/libposix/README Normal file
View File

@@ -0,0 +1,30 @@
libposix
Copyright (C) 2007 Bahadir Balban
Despite the name, this is a library that supports only a tiny portion of posix functions.
Currently supported functions are:
Functions to be supported in the near future are:
shmat
shmget
shmdt
mmap
munmap
read
write
lseek
open
close
creat
unlink
fork
execve
getpid
New ones will be added as needed.

73
tasks/libposix/SConstruct Normal file
View File

@@ -0,0 +1,73 @@
#
# Copyright (C) 2007 Bahadir Balban
#
import os
import glob
import sys
from os.path import join
from string import split
project_root = "../.."
kernel_headers = join(project_root, "include")
l4lib_headers = join(project_root, "tasks/libl4/include")
config_h = join(project_root, "include/l4/config.h")
env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
CCFLAGS = ['-g', '-nostdlib', '-ffreestanding'],
LINKFLAGS = ['-nostdlib'],
ENV = {'PATH' : os.environ['PATH']},
LIBS = 'gcc')
def extract_arch_subarch_plat(config_header):
'''
From the autogenerated kernel config.h, extracts platform, archictecture,
subarchitecture information. This is used to include the relevant headers
from the kernel directories.
'''
arch = None
subarch = None
plat = None
if not os.path.exists(config_header):
print "\n\nconfig.h does not exist. "\
"Please run: `scons configure' first\n\n"
sys.exit()
f = open(config_h, "r")
while True:
line = f.readline()
if line == "":
break
parts = split(line)
if len(parts) > 0:
if parts[0] == "#define":
if parts[1] == "__ARCH__":
arch = parts[2]
elif parts[1] == "__PLATFORM__":
plat = parts[2]
elif parts[1] == "__SUBARCH__":
subarch = parts[2]
f.close()
if arch == None:
print "Error: No config symbol found for architecture"
sys.exit()
if subarch == None:
print "Error: No config symbol found for subarchitecture"
sys.exit()
if plat == None:
print "Error: No config symbol found for platform"
sys.exit()
return arch, subarch, plat
arch, subarch, plat = extract_arch_subarch_plat(config_h)
headers = ["#include/posix", l4lib_headers, kernel_headers]
env.Append(CPPPATH = headers)
src = glob.glob("src/*.c") + glob.glob("*.c")
libposix = env.StaticLibrary('posix', src)

8
tasks/libposix/errno.c Normal file
View File

@@ -0,0 +1,8 @@
#include <errno.h>
int errno;
int *__errno_location(void)
{
return &errno;
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
*
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
#include <features.h>
#ifdef __UCLIBC_HAS_LFS__
#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS != 64
#undef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif
#ifndef __USE_LARGEFILE64
# define __USE_LARGEFILE64 1
#endif
/* We absolutely do _NOT_ want interfaces silently
* renamed under us or very bad things will happen... */
#ifdef __USE_FILE_OFFSET64
# undef __USE_FILE_OFFSET64
#endif
#else
# error Do not include this header in files not built when LFS is disabled
#endif

View File

@@ -0,0 +1,5 @@
#ifdef _LIBC
# include_next <linux/a.out.h>
#else
# include <linux/a.out.h>
#endif

View File

@@ -0,0 +1,43 @@
/* Copyright (C) 1992, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _ALLOCA_H
#define _ALLOCA_H 1
#include <features.h>
#define __need_size_t
#include <stddef.h>
__BEGIN_DECLS
/* Remove any previous definitions. */
#undef alloca
/* Allocate a block that will be freed when the calling function exits. */
extern void *alloca (size_t __size) __THROW;
#ifdef __GNUC__
# define alloca(size) __builtin_alloca (size)
#endif /* GCC. */
#define __MAX_ALLOCA_CUTOFF 65536
__END_DECLS
#endif /* alloca.h */

View File

@@ -0,0 +1,48 @@
/* Header describing `ar' archive file format.
Copyright (C) 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _AR_H
#define _AR_H 1
#include <sys/cdefs.h>
/* Archive files start with the ARMAG identifying string. Then follows a
`struct ar_hdr', and as many bytes of member file data as its `ar_size'
member indicates, for each member file. */
#define ARMAG "!<arch>\n" /* String that begins an archive file. */
#define SARMAG 8 /* Size of that string. */
#define ARFMAG "`\n" /* String in ar_fmag at end of each header. */
__BEGIN_DECLS
struct ar_hdr
{
char ar_name[16]; /* Member file name, sometimes / terminated. */
char ar_date[12]; /* File date, decimal seconds since Epoch. */
char ar_uid[6], ar_gid[6]; /* User and group IDs, in ASCII decimal. */
char ar_mode[8]; /* File mode, in ASCII octal. */
char ar_size[10]; /* File size, in ASCII decimal. */
char ar_fmag[2]; /* Always contains ARFMAG. */
};
__END_DECLS
#endif /* ar.h */

View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 1983, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ftp.h 8.1 (Berkeley) 6/2/93
*/
#ifndef _ARPA_FTP_H
#define _ARPA_FTP_H 1
/* Definitions for FTP; see RFC-765. */
/*
* Reply codes.
*/
#define PRELIM 1 /* positive preliminary */
#define COMPLETE 2 /* positive completion */
#define CONTINUE 3 /* positive intermediate */
#define TRANSIENT 4 /* transient negative completion */
#define ERROR 5 /* permanent negative completion */
/*
* Type codes
*/
#define TYPE_A 1 /* ASCII */
#define TYPE_E 2 /* EBCDIC */
#define TYPE_I 3 /* image */
#define TYPE_L 4 /* local byte size */
#ifdef FTP_NAMES
char *typenames[] = {"0", "ASCII", "EBCDIC", "Image", "Local" };
#endif
/*
* Form codes
*/
#define FORM_N 1 /* non-print */
#define FORM_T 2 /* telnet format effectors */
#define FORM_C 3 /* carriage control (ASA) */
#ifdef FTP_NAMES
char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" };
#endif
/*
* Structure codes
*/
#define STRU_F 1 /* file (no record structure) */
#define STRU_R 2 /* record structure */
#define STRU_P 3 /* page structure */
#ifdef FTP_NAMES
char *strunames[] = {"0", "File", "Record", "Page" };
#endif
/*
* Mode types
*/
#define MODE_S 1 /* stream */
#define MODE_B 2 /* block */
#define MODE_C 3 /* compressed */
#ifdef FTP_NAMES
char *modenames[] = {"0", "Stream", "Block", "Compressed" };
#endif
/*
* Record Tokens
*/
#define REC_ESC '\377' /* Record-mode Escape */
#define REC_EOR '\001' /* Record-mode End-of-Record */
#define REC_EOF '\002' /* Record-mode End-of-File */
/*
* Block Header
*/
#define BLK_EOR 0x80 /* Block is End-of-Record */
#define BLK_EOF 0x40 /* Block is End-of-File */
#define BLK_ERRORS 0x20 /* Block is suspected of containing errors */
#define BLK_RESTART 0x10 /* Block is Restart Marker */
#define BLK_BYTECOUNT 2 /* Bytes in this block */
#endif /* arpa/ftp.h */

View File

@@ -0,0 +1,106 @@
/* Copyright (C) 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _ARPA_INET_H
#define _ARPA_INET_H 1
#include <features.h>
#include <netinet/in.h> /* To define `struct in_addr'. */
/* Type for length arguments in socket calls. */
#ifndef __socklen_t_defined
typedef __socklen_t socklen_t;
# define __socklen_t_defined
#endif
__BEGIN_DECLS
/* Convert Internet host address from numbers-and-dots notation in CP
into binary data in network byte order. */
extern in_addr_t inet_addr (__const char *__cp) __THROW;
/* Return the local host address part of the Internet address in IN. */
extern in_addr_t inet_lnaof (struct in_addr __in) __THROW;
/* Make Internet host address in network byte order by combining the
network number NET with the local address HOST. */
extern struct in_addr inet_makeaddr (in_addr_t __net, in_addr_t __host)
__THROW;
/* Return network number part of the Internet address IN. */
extern in_addr_t inet_netof (struct in_addr __in) __THROW;
/* Extract the network number in network byte order from the address
in numbers-and-dots natation starting at CP. */
extern in_addr_t inet_network (__const char *__cp) __THROW;
/* Convert Internet number in IN to ASCII representation. The return value
is a pointer to an internal array containing the string. */
extern char *inet_ntoa (struct in_addr __in) __THROW;
/* Convert from presentation format of an Internet number in buffer
starting at CP to the binary network format and store result for
interface type AF in buffer starting at BUF. */
extern int inet_pton (int __af, __const char *__restrict __cp,
void *__restrict __buf) __THROW;
/* Convert a Internet address in binary network format for interface
type AF in buffer starting at CP to presentation form and place
result in buffer of length LEN astarting at BUF. */
extern __const char *inet_ntop (int __af, __const void *__restrict __cp,
char *__restrict __buf, socklen_t __len)
__THROW;
/* The following functions are not part of XNS 5.2. */
#ifdef __USE_MISC
/* Convert Internet host address from numbers-and-dots notation in CP
into binary data and store the result in the structure INP. */
extern int inet_aton (__const char *__cp, struct in_addr *__inp) __THROW;
/* Format a network number NET into presentation format and place result
in buffer starting at BUF with length of LEN bytes. */
extern char *inet_neta (in_addr_t __net, char *__buf, size_t __len) __THROW;
/* Convert network number for interface type AF in buffer starting at
CP to presentation format. The result will specifiy BITS bits of
the number. */
extern char *inet_net_ntop (int __af, __const void *__cp, int __bits,
char *__buf, size_t __len) __THROW;
/* Convert network number for interface type AF from presentation in
buffer starting at CP to network format and store result int
buffer starting at BUF of size LEN. */
extern int inet_net_pton (int __af, __const char *__cp,
void *__buf, size_t __len) __THROW;
/* Convert ASCII representation in hexadecimal form of the Internet
address to binary form and place result in buffer of length LEN
starting at BUF. */
extern unsigned int inet_nsap_addr (__const char *__cp,
unsigned char *__buf, int __len) __THROW;
/* Convert internet address in binary form in LEN bytes starting at CP
a presentation form and place result in BUF. */
extern char *inet_nsap_ntoa (int __len, __const unsigned char *__cp,
char *__buf) __THROW;
#endif
__END_DECLS
#endif /* arpa/inet.h */

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