mirror of
https://github.com/drasko/codezero.git
synced 2026-02-26 16:53:14 +01:00
Initial commit
This commit is contained in:
213
tasks/.config
Normal file
213
tasks/.config
Normal 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
130
tasks/blkdev0/SConstruct
Normal 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)
|
||||
|
||||
43
tasks/blkdev0/fsbin/SConstruct
Normal file
43
tasks/blkdev0/fsbin/SConstruct
Normal 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)
|
||||
7
tasks/blkdev0/fsbin/incbin.S
Normal file
7
tasks/blkdev0/fsbin/incbin.S
Normal 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
1
tasks/blkdev0/include/arch
Symbolic link
@@ -0,0 +1 @@
|
||||
arch-arm
|
||||
23
tasks/blkdev0/include/blkdev.h
Normal file
23
tasks/blkdev0/include/blkdev.h
Normal 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__ */
|
||||
43
tasks/blkdev0/include/linker.lds
Normal file
43
tasks/blkdev0/include/linker.lds
Normal 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 = .;
|
||||
}
|
||||
17
tasks/blkdev0/include/physical_base.lds
Normal file
17
tasks/blkdev0/include/physical_base.lds
Normal 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;
|
||||
6
tasks/blkdev0/include/ramdisk.h
Normal file
6
tasks/blkdev0/include/ramdisk.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef __RAMDISK_H__
|
||||
#define __RAMDISK_H__
|
||||
|
||||
extern struct block_device ramdisk;
|
||||
|
||||
#endif
|
||||
10
tasks/blkdev0/main.c
Normal file
10
tasks/blkdev0/main.c
Normal 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
1
tasks/blkdev0/src/arch
Symbolic link
@@ -0,0 +1 @@
|
||||
arch-arm
|
||||
10
tasks/blkdev0/src/init.c
Normal file
10
tasks/blkdev0/src/init.c
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
#include <blkdev.h>
|
||||
#include <ramdisk.h>
|
||||
|
||||
|
||||
void init_blkdev(void)
|
||||
{
|
||||
ramdisk.ops.open(&ramdisk);
|
||||
}
|
||||
65
tasks/blkdev0/src/ramdisk.c
Normal file
65
tasks/blkdev0/src/ramdisk.c
Normal 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,
|
||||
},
|
||||
};
|
||||
|
||||
28
tasks/blkdev0/tools/generate_bootdesc.py
Executable file
28
tasks/blkdev0/tools/generate_bootdesc.py
Executable 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
123
tasks/bootdesc/SConstruct
Normal 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)
|
||||
23
tasks/bootdesc/bootdesc.c.append
Normal file
23
tasks/bootdesc/bootdesc.c.append
Normal 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,
|
||||
},
|
||||
|
||||
},
|
||||
};
|
||||
39
tasks/bootdesc/bootdesc.c.orig
Normal file
39
tasks/bootdesc/bootdesc.c.orig
Normal 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,
|
||||
},
|
||||
|
||||
},
|
||||
};
|
||||
16
tasks/bootdesc/bootdesc.c.templ
Normal file
16
tasks/bootdesc/bootdesc.c.templ
Normal 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
3
tasks/bootdesc/fs0.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
fs0
|
||||
image_start 0x218000
|
||||
image_end 0x21B26C
|
||||
3
tasks/bootdesc/inittask.txt
Normal file
3
tasks/bootdesc/inittask.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
inittask
|
||||
image_start 0x208000
|
||||
image_end 0x213260
|
||||
8
tasks/bootdesc/linker.lds
Normal file
8
tasks/bootdesc/linker.lds
Normal file
@@ -0,0 +1,8 @@
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
_start = .;
|
||||
.data : { *(.data) }
|
||||
_end = .;
|
||||
}
|
||||
3
tasks/bootdesc/mm0.txt
Normal file
3
tasks/bootdesc/mm0.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
mm0
|
||||
image_start 0x208000
|
||||
image_end 0x213140
|
||||
3
tasks/bootdesc/romfs.txt
Normal file
3
tasks/bootdesc/romfs.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
romfs
|
||||
image_start 0x220000
|
||||
image_end 0x268800
|
||||
3
tasks/bootdesc/roottask.txt
Normal file
3
tasks/bootdesc/roottask.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
roottask
|
||||
image_start 0x218000
|
||||
image_end 0x21B344
|
||||
3
tasks/bootdesc/start.txt
Normal file
3
tasks/bootdesc/start.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
start
|
||||
image_start 0x100000
|
||||
image_end 0x205800
|
||||
3
tasks/bootdesc/test0.txt
Normal file
3
tasks/bootdesc/test0.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
test0
|
||||
image_start 0x218000
|
||||
image_end 0x21AEDC
|
||||
3
tasks/bootdesc/testtask.txt
Normal file
3
tasks/bootdesc/testtask.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
testtask
|
||||
image_start 0x220000
|
||||
image_end 0x223344
|
||||
0
tasks/fs0/MAKE_SURE_TO_SET_VFS_TID
Normal file
0
tasks/fs0/MAKE_SURE_TO_SET_VFS_TID
Normal file
66
tasks/fs0/SConstruct
Normal file
66
tasks/fs0/SConstruct
Normal 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
8
tasks/fs0/include/bdev.h
Normal 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
90
tasks/fs0/include/fs.h
Normal 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
26
tasks/fs0/include/kdata.h
Normal 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__ */
|
||||
36
tasks/fs0/include/linker.lds
Normal file
36
tasks/fs0/include/linker.lds
Normal 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
7
tasks/fs0/include/task.h
Normal 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
82
tasks/fs0/main.c
Normal 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
0
tasks/fs0/src/dentry.c
Normal file
63
tasks/fs0/src/kdata.c
Normal file
63
tasks/fs0/src/kdata.c
Normal 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
0
tasks/fs0/src/mount.c
Normal file
86
tasks/fs0/src/romfs/romfs.c
Normal file
86
tasks/fs0/src/romfs/romfs.c
Normal 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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
43
tasks/fs0/src/romfs/romfs.h
Normal file
43
tasks/fs0/src/romfs/romfs.h
Normal 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__ */
|
||||
61
tasks/fs0/src/romfs/romfs_fs.h
Normal file
61
tasks/fs0/src/romfs/romfs_fs.h
Normal 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
0
tasks/fs0/src/sb.c
Normal file
31
tasks/fs0/src/simplefs/inode.c
Normal file
31
tasks/fs0/src/simplefs/inode.c
Normal 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
28
tasks/fs0/src/vfs.c
Normal 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
0
tasks/fs0/src/vnode.c
Normal file
27
tasks/fs0/tools/generate_bootdesc.py
Executable file
27
tasks/fs0/tools/generate_bootdesc.py
Executable 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
78
tasks/libl4/SConstruct
Normal 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)
|
||||
|
||||
|
||||
1
tasks/libl4/include/l4lib/arch
Symbolic link
1
tasks/libl4/include/l4lib/arch
Symbolic link
@@ -0,0 +1 @@
|
||||
arch-arm
|
||||
15
tasks/libl4/include/l4lib/arch-arm/asm.h
Normal file
15
tasks/libl4/include/l4lib/arch-arm/asm.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef __ARM_ASM_H__
|
||||
#define __ARM_ASM_H__
|
||||
|
||||
#define BEGIN_PROC(name) \
|
||||
.global name; \
|
||||
.type name,function; \
|
||||
.align; \
|
||||
name:
|
||||
|
||||
#define END_PROC(name) \
|
||||
.fend_##name: \
|
||||
.size name,.fend_##name - name;
|
||||
|
||||
#endif /* __ARM_ASM_H__ */
|
||||
|
||||
26
tasks/libl4/include/l4lib/arch-arm/message.h
Normal file
26
tasks/libl4/include/l4lib/arch-arm/message.h
Normal 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__ */
|
||||
83
tasks/libl4/include/l4lib/arch-arm/syscalls.h
Normal file
83
tasks/libl4/include/l4lib/arch-arm/syscalls.h
Normal 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__ */
|
||||
|
||||
179
tasks/libl4/include/l4lib/arch-arm/syslib.h
Normal file
179
tasks/libl4/include/l4lib/arch-arm/syslib.h
Normal 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__ */
|
||||
12
tasks/libl4/include/l4lib/arch-arm/types.h
Normal file
12
tasks/libl4/include/l4lib/arch-arm/types.h
Normal 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
|
||||
43
tasks/libl4/include/l4lib/arch-arm/utcb.h
Normal file
43
tasks/libl4/include/l4lib/arch-arm/utcb.h
Normal 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__ */
|
||||
13
tasks/libl4/include/l4lib/arch-arm/vregs.h
Normal file
13
tasks/libl4/include/l4lib/arch-arm/vregs.h
Normal 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__ */
|
||||
|
||||
42
tasks/libl4/include/l4lib/ipcdefs.h
Normal file
42
tasks/libl4/include/l4lib/ipcdefs.h
Normal 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__ */
|
||||
15
tasks/libl4/include/l4lib/kip.h
Normal file
15
tasks/libl4/include/l4lib/kip.h
Normal 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__ */
|
||||
17
tasks/libl4/include/l4lib/types.h
Normal file
17
tasks/libl4/include/l4lib/types.h
Normal 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__ */
|
||||
10
tasks/libl4/include/l4lib/utcb.h
Normal file
10
tasks/libl4/include/l4lib/utcb.h
Normal 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__ */
|
||||
157
tasks/libl4/src/arm/syscalls.S
Normal file
157
tasks/libl4/src/arm/syscalls.S
Normal 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
40
tasks/libl4/src/init.c
Normal 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
20
tasks/libl4/tagfilelist
Normal 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
67
tasks/libmem/SConstruct
Normal 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)
|
||||
|
||||
363
tasks/libmem/kmalloc/kmalloc.c
Normal file
363
tasks/libmem/kmalloc/kmalloc.c
Normal 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;
|
||||
}
|
||||
|
||||
457
tasks/libmem/kmalloc/kmalloc.c.orig
Normal file
457
tasks/libmem/kmalloc/kmalloc.c.orig
Normal 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;
|
||||
}
|
||||
|
||||
31
tasks/libmem/kmalloc/kmalloc.h
Normal file
31
tasks/libmem/kmalloc/kmalloc.h
Normal 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__ */
|
||||
|
||||
28
tasks/libmem/kmalloc/kmalloc.h.orig
Normal file
28
tasks/libmem/kmalloc/kmalloc.h.orig
Normal 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__ */
|
||||
|
||||
202
tasks/libmem/memcache/memcache.c
Normal file
202
tasks/libmem/memcache/memcache.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
50
tasks/libmem/memcache/memcache.h
Normal file
50
tasks/libmem/memcache/memcache.h
Normal 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__ */
|
||||
266
tasks/libmem/mm/alloc_page.c
Normal file
266
tasks/libmem/mm/alloc_page.c
Normal 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);
|
||||
}
|
||||
|
||||
36
tasks/libmem/mm/alloc_page.h
Normal file
36
tasks/libmem/mm/alloc_page.h
Normal 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
110
tasks/libmem/run_tests.py
Executable 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()
|
||||
|
||||
9
tasks/libmem/tests/SConscript
Normal file
9
tasks/libmem/tests/SConscript
Normal 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
16
tasks/libmem/tests/clz.c
Normal 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
7
tasks/libmem/tests/clz.h
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
#ifndef __CLZ_H__
|
||||
#define __CLZ_H__
|
||||
|
||||
unsigned int __clz(unsigned int bitvector);
|
||||
|
||||
#endif /* __CLZ_H__ */
|
||||
33
tasks/libmem/tests/debug.c
Normal file
33
tasks/libmem/tests/debug.c
Normal 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);
|
||||
}
|
||||
|
||||
17
tasks/libmem/tests/debug.h
Normal file
17
tasks/libmem/tests/debug.h
Normal 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 */
|
||||
28
tasks/libmem/tests/libl4.c
Normal file
28
tasks/libmem/tests/libl4.c
Normal 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;
|
||||
}
|
||||
|
||||
17
tasks/libmem/tests/libl4.h
Normal file
17
tasks/libmem/tests/libl4.h
Normal 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
|
||||
0
tasks/libmem/tests/linker.c
Normal file
0
tasks/libmem/tests/linker.c
Normal file
250
tasks/libmem/tests/main.c
Normal file
250
tasks/libmem/tests/main.c
Normal 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;
|
||||
}
|
||||
|
||||
9
tasks/libmem/tests/memory.c
Normal file
9
tasks/libmem/tests/memory.c
Normal 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;
|
||||
|
||||
216
tasks/libmem/tests/test_alloc_generic.c
Normal file
216
tasks/libmem/tests/test_alloc_generic.c
Normal 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;
|
||||
}
|
||||
|
||||
29
tasks/libmem/tests/test_alloc_generic.h
Normal file
29
tasks/libmem/tests/test_alloc_generic.h
Normal 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__ */
|
||||
85
tasks/libmem/tests/test_allocpage.c
Normal file
85
tasks/libmem/tests/test_allocpage.c
Normal 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);
|
||||
}
|
||||
13
tasks/libmem/tests/test_allocpage.h
Normal file
13
tasks/libmem/tests/test_allocpage.h
Normal 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
|
||||
42
tasks/libmem/tests/test_kmalloc.c
Normal file
42
tasks/libmem/tests/test_kmalloc.c
Normal 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);
|
||||
}
|
||||
|
||||
8
tasks/libmem/tests/test_kmalloc.h
Normal file
8
tasks/libmem/tests/test_kmalloc.h
Normal 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
|
||||
115
tasks/libmem/tests/test_memcache.c
Normal file
115
tasks/libmem/tests/test_memcache.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
10
tasks/libmem/tests/test_memcache.h
Normal file
10
tasks/libmem/tests/test_memcache.h
Normal 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__ */
|
||||
|
||||
21
tasks/libmem/tests/tests.h
Normal file
21
tasks/libmem/tests/tests.h
Normal 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
30
tasks/libposix/README
Normal 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
73
tasks/libposix/SConstruct
Normal 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
8
tasks/libposix/errno.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <errno.h>
|
||||
|
||||
int errno;
|
||||
|
||||
int *__errno_location(void)
|
||||
{
|
||||
return &errno;
|
||||
}
|
||||
29
tasks/libposix/include/posix/_lfs_64.h
Normal file
29
tasks/libposix/include/posix/_lfs_64.h
Normal 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
|
||||
5
tasks/libposix/include/posix/a.out.h
Normal file
5
tasks/libposix/include/posix/a.out.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#ifdef _LIBC
|
||||
# include_next <linux/a.out.h>
|
||||
#else
|
||||
# include <linux/a.out.h>
|
||||
#endif
|
||||
43
tasks/libposix/include/posix/alloca.h
Normal file
43
tasks/libposix/include/posix/alloca.h
Normal 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 */
|
||||
48
tasks/libposix/include/posix/ar.h
Normal file
48
tasks/libposix/include/posix/ar.h
Normal 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 */
|
||||
105
tasks/libposix/include/posix/arpa/ftp.h
Normal file
105
tasks/libposix/include/posix/arpa/ftp.h
Normal 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 */
|
||||
106
tasks/libposix/include/posix/arpa/inet.h
Normal file
106
tasks/libposix/include/posix/arpa/inet.h
Normal 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
Reference in New Issue
Block a user