diff --git a/conts/posix/SConstruct b/conts/posix/SConstruct
new file mode 100644
index 0000000..baf0b34
--- /dev/null
+++ b/conts/posix/SConstruct
@@ -0,0 +1,90 @@
+# -*- mode: python; coding: utf-8; -*-
+#
+# Codezero -- Virtualization microkernel for embedded systems.
+#
+# Copyright © 2009 B Labs Ltd
+#
+import os, shelve, sys
+from os.path import *
+
+PROJRELROOT = '../../'
+
+sys.path.append(PROJRELROOT)
+
+from config.projpaths import *
+from config.configuration import *
+
+config = configuration_retrieve()
+arch = config.arch
+
+
+LIBL4_RELDIR = 'conts/libl4'
+KERNEL_INCLUDE = join(PROJROOT, 'include')
+LIBL4_DIR = join(PROJROOT, LIBL4_RELDIR)
+LIBL4_INCLUDE = join(LIBL4_DIR, 'include')
+LIBL4_LIBPATH = join(BUILDDIR, LIBL4_RELDIR)
+
+# Locally important paths are here
+LIBC_RELDIR = 'conts/libc'
+LIBC_DIR = join(PROJROOT, LIBC_RELDIR)
+LIBC_LIBPATH = join(BUILDDIR, LIBC_RELDIR)
+LIBC_INCLUDE = [join(LIBC_DIR, 'include'), \
+ join(LIBC_DIR, 'include/arch' + '/' + arch)]
+
+LIBMEM_RELDIR = 'conts/libmem'
+LIBMEM_DIR = join(PROJROOT, LIBMEM_RELDIR)
+LIBMEM_LIBPATH = join(BUILDDIR, LIBMEM_RELDIR)
+LIBMEM_INCLUDE = LIBMEM_DIR
+
+LIBPOSIX_RELDIR = 'conts/posix/libposix'
+LIBPOSIX_DIR = join(PROJROOT, LIBPOSIX_RELDIR)
+LIBPOSIX_INCLUDE_SERVER = join(LIBPOSIX_DIR, 'include')
+LIBPOSIX_INCLUDE_USERSPACE = join(LIBPOSIX_DIR, 'include/posix')
+LIBPOSIX_LIBPATH = join(BUILDDIR, LIBPOSIX_RELDIR)
+
+env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
+ CCFLAGS = ['-g', '-nostdlib', '-ffreestanding', \
+ '-std=gnu99', '-Wall', '-Werror'],
+ LINKFLAGS = ['-nostdlib'], \
+ ASFLAGS = ['-D__ASSEMBLY__'],
+ PROGSUFFIX = '.elf',
+ ENV = {'PATH' : os.environ['PATH']},
+ LIBS = ['gcc', 'libl4', 'c-userspace', 'libmm', 'libmc', 'gcc'],
+ CPPPATH = ['include', LIBC_INCLUDE, KERNEL_INCLUDE, LIBL4_INCLUDE, LIBMEM_INCLUDE],
+ LIBPATH = [LIBC_LIBPATH, LIBL4_LIBPATH, LIBMEM_LIBPATH, LIBPOSIX_LIBPATH],
+ CPPFLAGS = '-include l4/config.h -include l4/macros.h -include l4/types.h')
+
+contid = ARGUMENTS.get('cont', '0')
+
+libposix = SConscript('libposix/SConscript', \
+ exports = { 'config' : config, 'env' : env, 'contid' : contid}, duplicate = 0, \
+ variant_dir = join(BUILDDIR, 'conts' + '/posix' + '/libposix'))
+
+mm0_env = env.Clone()
+mm0_env.Append(CPPPATH = LIBPOSIX_INCLUDE_SERVER)
+mm0 = SConscript('mm0/SConscript', \
+ exports = { 'config' : config, 'env' : mm0_env, 'contid' : contid}, duplicate = 0, \
+ variant_dir = join(BUILDDIR, 'cont' + str(contid) + '/posix' + '/mm0'))
+
+fs0_env = env.Clone()
+fs0_env.Append(CPPPATH = LIBPOSIX_INCLUDE_SERVER)
+fs0 = SConscript('fs0/SConscript', \
+ exports = { 'config' : config, 'env' : fs0_env, 'contid' : contid}, duplicate = 0, \
+ variant_dir = join(BUILDDIR, 'cont' + str(contid) + '/posix' + '/fs0'))
+
+test0_env = env.Clone()
+test0_env.Replace(CPPPATH = [LIBPOSIX_INCLUDE_USERSPACE, 'include', LIBC_INCLUDE, KERNEL_INCLUDE, LIBL4_INCLUDE, LIBMEM_INCLUDE])
+test0_env.Append(CCFLAGS = '-nostdinc')
+test0 = SConscript('test0/SConscript', \
+ exports = { 'config' : config, 'environment' : test0_env, 'contid' : contid}, duplicate = 0, \
+ variant_dir = join(BUILDDIR, 'cont' + str(contid) + '/posix' + '/test0'))
+
+Depends(fs0, libposix)
+Depends(test0, libposix)
+
+Alias('libposix', libposix)
+Alias('mm0', mm0)
+Alias('fs0', fs0)
+Alias('test0', test0)
+
+Default([mm0, fs0, libposix, test0])
diff --git a/conts/posix/bootdesc/SConscript b/conts/posix/bootdesc/SConscript
new file mode 100644
index 0000000..6dd82a5
--- /dev/null
+++ b/conts/posix/bootdesc/SConscript
@@ -0,0 +1,97 @@
+# -*- mode: python; coding: utf-8; -*-
+
+# Codezero -- a microkernel for embedded systems.
+#
+# Copyright © 2009 B Labs Ltd
+#
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU
+# General Public License as published by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public
+# License for more details.
+#
+# You should have received a copy of the GNU General Public License along with this program. If not, see
+# .
+#
+# Author: Russel Winder
+
+import os.path
+import subprocess
+import shutil
+
+Import('environment', 'images')
+
+e = environment.Clone()
+e.Append(LINKFLAGS = ['-T' + e['posixServicesDirectory'] + '/bootdesc/linker.lds'])
+e.Append(CPPPATH = ['#' + e['includeDirectory']])
+
+bootdescTemplate = \
+'''
+/* This file is autogenerated, do not edit by hand. */
+
+/* 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) * %s,
+ .total_images = %s,
+ .images = {
+%s
+ },
+};
+'''
+
+imageTemplate = \
+''' [%s] = {
+ .name = "%s",
+ .phys_start = %s,
+ .phys_end = %s,
+ },
+'''
+
+def generateLocationData(image):
+ process = subprocess.Popen('tools/pyelf/readelf.py --lma-start-end ' + image.path, shell=True, stdout=subprocess.PIPE)
+ assert process.wait() == 0
+ return (process.stdout.readline().strip(), process.stdout.readline().strip().split()[1], process.stdout.readline().strip().split()[1])
+
+def generateBootdesc(target, source, env):
+ '''
+ Extracts name, start, end information from the kernel and each svc task.
+ Uses this information to produce bootdesc.c
+ '''
+ with open(target[0].path, 'w' ) as f:
+ imagesString = ''
+ numberOfImages = len(source) - 1
+ for index in range(1, len(source)):
+ imagesString += imageTemplate % ((index - 1,) + generateLocationData(source[index]))
+ f.write(bootdescTemplate % (numberOfImages, numberOfImages, imagesString))
+
+def relocateBootdesc(target, source, env):
+ name, start, end = generateLocationData(source[1])
+ print "arm-none-linux-gnueabi-objcopy" + " --adjust-section-vma .data=" + end + " " + source[0].path
+# process = subprocess.Popen(executable='arm-none-linux-gnueabi-objcopy', args=(
+# '--adjust-section-vma .data=' + end,
+# source[0].path))
+# assert process.wait() == 0
+ os.system("arm-none-linux-gnueabi-objcopy --adjust-section-vma .data=" + end + " " + source[0].path)
+ shutil.copyfile(source[0].path, target[0].path)
+
+objects = e.Object(e.Command('bootdesc.c', images, generateBootdesc))
+Depends(objects, e['configFiles'])
+bootdesc = e.Command('bootdesc.axf', e.Program('bootdesc_intermediate', objects) + [images[1]] , relocateBootdesc)
+Depends(bootdesc, e['configFiles'])
+
+Return('bootdesc')
diff --git a/conts/posix/bootdesc/SConstruct b/conts/posix/bootdesc/SConstruct
new file mode 100644
index 0000000..7eb14cf
--- /dev/null
+++ b/conts/posix/bootdesc/SConstruct
@@ -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, fs0, test0]
+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)
diff --git a/conts/posix/bootdesc/bootdesc.c.templ b/conts/posix/bootdesc/bootdesc.c.templ
new file mode 100644
index 0000000..0b6aa49
--- /dev/null
+++ b/conts/posix/bootdesc/bootdesc.c.templ
@@ -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__));
+
diff --git a/conts/posix/bootdesc/linker.lds b/conts/posix/bootdesc/linker.lds
new file mode 100644
index 0000000..06b95ec
--- /dev/null
+++ b/conts/posix/bootdesc/linker.lds
@@ -0,0 +1,8 @@
+ENTRY(_start)
+
+SECTIONS
+{
+ _start = .;
+ .data : { *(.data) }
+ _end = .;
+}
diff --git a/conts/posix/fs0/SConscript b/conts/posix/fs0/SConscript
new file mode 100644
index 0000000..0356014
--- /dev/null
+++ b/conts/posix/fs0/SConscript
@@ -0,0 +1,17 @@
+
+Import('config', 'env', 'contid')
+
+import os, sys
+
+arch = config.arch
+
+src = [Glob('*.c') + Glob('src/*.c') + Glob('src/arch/arm/*.c') + Glob('src/memfs/*.c') + Glob('src/lib/*.c')]
+
+e = env.Clone()
+e.Append(LIBS = 'posix')
+e.Append(LINKFLAGS = ['-T' + "fs0/include/linker.lds", '-u_start'])
+
+objs = e.Object(src)
+fs0 = e.Program('fs0.elf', objs)
+
+Return('fs0')
diff --git a/conts/posix/fs0/SConstruct b/conts/posix/fs0/SConstruct
new file mode 100644
index 0000000..6c6b1e3
--- /dev/null
+++ b/conts/posix/fs0/SConstruct
@@ -0,0 +1,75 @@
+#
+# 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/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
+
+#libmem paths:
+libmem_path = "../libmem"
+libmem_incpath = "../libmem"
+
+# libl4 paths:
+libl4_path = "../libl4"
+libl4_incpath1 = join(libl4_path, "include")
+
+# libposix paths:
+libposix_path = "../libposix"
+libposix_incpath = join(libposix_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,\
+ "-L" + libmem_path, "-L" + libposix_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', 'libmc', 'libl4', 'gcc', libc_name, "posix"],
+ CPPFLAGS = "-D__USERSPACE__",
+ CPPPATH = ['#include', libl4_incpath1, kernel_incpath, libc_incpath, \
+ libposix_incpath, libmem_incpath])
+
+src = [glob("src/*.c"), glob("*.c"), glob("src/arch/arm/*.c"), glob("src/memfs/*.c"), glob("src/lib/*.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)
diff --git a/conts/posix/fs0/container.c b/conts/posix/fs0/container.c
new file mode 100644
index 0000000..8b3311f
--- /dev/null
+++ b/conts/posix/fs0/container.c
@@ -0,0 +1,23 @@
+/*
+ * Container entry point for this task
+ *
+ * Copyright (C) 2007-2009 Bahadir Bilgehan Balban
+ */
+#include
+#include
+#include
+
+void main(void);
+
+void __container_init(void)
+{
+ /* Generic L4 thread initialisation */
+ __l4_init();
+
+ /* FS0 posix-service initialisation */
+ posix_service_init();
+
+ /* Entry to main */
+ main();
+}
+
diff --git a/conts/posix/fs0/include/bdev.h b/conts/posix/fs0/include/bdev.h
new file mode 100644
index 0000000..c85a0cd
--- /dev/null
+++ b/conts/posix/fs0/include/bdev.h
@@ -0,0 +1,8 @@
+#ifndef __BDEV_H__
+#define __BDEV_H__
+/*
+ * This is a mock-up compiled in blockdev buffer, to be used temporarily.
+ */
+
+void *vfs_rootdev_open(void);
+#endif/* __BDEV_H__ */
diff --git a/conts/posix/fs0/include/file.h b/conts/posix/fs0/include/file.h
new file mode 100644
index 0000000..a553e4b
--- /dev/null
+++ b/conts/posix/fs0/include/file.h
@@ -0,0 +1,6 @@
+#ifndef __FS0_MM_H__
+#define __FS0_MM_H__
+
+
+
+#endif /* __FS0_MM_H__ */
diff --git a/conts/posix/fs0/include/fs.h b/conts/posix/fs0/include/fs.h
new file mode 100644
index 0000000..20f7d49
--- /dev/null
+++ b/conts/posix/fs0/include/fs.h
@@ -0,0 +1,171 @@
+/*
+ * VFS definitions.
+ *
+ * Copyright (C) 2007, 2008 Bahadir Balban.
+ */
+#ifndef __FS_H__
+#define __FS_H__
+
+#include
+#include
+#include
+#include
+#include
+
+typedef void (*vnode_op_t)(void);
+typedef void (*file_op_t)(void);
+
+struct dentry;
+struct file;
+struct file_system_type;
+struct superblock;
+struct vnode;
+
+struct dentry_ops {
+ int (*compare)(struct dentry *d, const char *n);
+};
+
+/* Operations that work on file content */
+struct file_ops {
+
+ /* Read a vnode's contents by page range */
+ int (*read)(struct vnode *v, unsigned long pfn,
+ unsigned long npages, void *buf);
+
+ /* Write a vnode's contents by page range */
+ int (*write)(struct vnode *v, unsigned long pfn,
+ unsigned long npages, void *buf);
+ file_op_t open;
+ file_op_t close;
+ file_op_t mmap;
+ file_op_t lseek;
+ file_op_t flush;
+ file_op_t fsync;
+};
+
+/* Operations that work on vnode fields and associations between vnodes */
+struct vnode_ops {
+ vnode_op_t create;
+ struct vnode *(*lookup)(struct vnode *root, struct pathdata *pdata,
+ const char *component);
+ int (*readdir)(struct vnode *v);
+ int (*filldir)(void *buf, struct vnode *v, int count);
+ vnode_op_t link;
+ vnode_op_t unlink;
+ int (*mkdir)(struct vnode *parent, const char *name);
+ struct vnode *(*mknod)(struct vnode *parent, const char *name,
+ unsigned int mode);
+ vnode_op_t rmdir;
+ vnode_op_t rename;
+ vnode_op_t getattr;
+ vnode_op_t setattr;
+};
+
+struct superblock_ops {
+ int (*write_sb)(struct superblock *sb);
+
+ /*
+ * Given a vnum, reads the disk-inode and copies its data
+ * into the vnode's generic fields
+ */
+ int (*read_vnode)(struct superblock *sb, struct vnode *v);
+
+ /* Writes vnode's generic fields into the disk-inode structure */
+ int (*write_vnode)(struct superblock *sb, struct vnode *v);
+
+ /* Allocates a disk-inode along with a vnode, and associates the two */
+ struct vnode *(*alloc_vnode)(struct superblock *sb);
+
+ /* Frees the vnode and the corresponding on-disk inode */
+ int (*free_vnode)(struct superblock *sb, struct vnode *v);
+};
+
+#define VFS_DNAME_MAX 256
+struct dentry {
+ int refcnt;
+ char name[VFS_DNAME_MAX];
+ struct dentry *parent; /* Parent dentry */
+ struct link child; /* List of dentries with same parent */
+ struct link children; /* List of children dentries */
+ struct link vref; /* For vnode's dirent reference list */
+ struct link cache_list; /* Dentry cache reference */
+ struct vnode *vnode; /* The vnode associated with dentry */
+ struct dentry_ops ops;
+};
+
+/*
+ * Buffer that maintains directory content for a directory vnode. This is the
+ * only vnode content that fs0 maintains. All other file data is in mm0 page
+ * cache.
+ */
+struct dirbuf {
+ unsigned long npages;
+ int dirty;
+ u8 *buffer;
+};
+
+/* Posix-style dirent format used by userspace. Returned by sys_readdir() */
+#define DIRENT_NAME_MAX 32
+struct dirent {
+ u32 inum; /* Inode number */
+ u32 offset; /* Dentry offset in its buffer */
+ u16 rlength; /* Record length */
+ u8 name[DIRENT_NAME_MAX]; /* Name string */
+};
+
+struct vnode {
+ unsigned long vnum; /* Filesystem-wide unique vnode id */
+ int refcnt; /* Reference counter */
+ int links; /* Number of hard links */
+ struct superblock *sb; /* Reference to superblock */
+ struct vnode_ops ops; /* Operations on this vnode */
+ struct file_ops fops; /* File-related operations on this vnode */
+ struct link dentries; /* Dirents that refer to this vnode */
+ struct link cache_list; /* For adding the vnode to vnode cache */
+ struct dirbuf dirbuf; /* Only directory buffers are kept */
+ u32 mode; /* Permissions and vnode type */
+ u32 owner; /* Owner */
+ u64 atime; /* Last access time */
+ u64 mtime; /* Last content modification */
+ u64 ctime; /* Last vnode modification */
+ u64 size; /* Size of contents */
+ void *inode; /* Ptr to fs-specific inode */
+};
+
+/* FS0 vfs specific macros */
+
+/* Check if directory */
+#define vfs_isdir(v) S_ISDIR((v)->mode)
+
+/* Set vnode type */
+#define vfs_set_type(v, type) {v->mode &= ~S_IFMT; v->mode |= S_IFMT & type; }
+
+struct fstype_ops {
+ struct superblock *(*get_superblock)(void *buf);
+};
+
+#define VFS_FSNAME_MAX 256
+struct file_system_type {
+ char name[VFS_FSNAME_MAX];
+ unsigned long magic;
+ struct fstype_ops ops;
+ struct link list; /* Member of list of all fs types */
+ struct link sblist; /* List of superblocks with this type */
+};
+struct superblock *get_superblock(void *buf);
+
+struct superblock {
+ u64 fssize;
+ unsigned int blocksize;
+ struct link list;
+ struct file_system_type *fs;
+ struct superblock_ops *ops;
+ struct vnode *root;
+ void *fs_super;
+};
+
+void vfs_mount_fs(struct superblock *sb);
+
+extern struct dentry_ops generic_dentry_operations;
+
+#endif /* __FS_H__ */
diff --git a/conts/posix/fs0/include/globals.h b/conts/posix/fs0/include/globals.h
new file mode 100644
index 0000000..50f588d
--- /dev/null
+++ b/conts/posix/fs0/include/globals.h
@@ -0,0 +1,13 @@
+#ifndef __GLOBALS_H__
+#define __GLOBALS_H__
+
+struct global_list {
+ int total;
+ struct link list;
+};
+
+extern struct global_list global_vm_files;
+extern struct global_list global_vm_objects;
+extern struct global_list global_tasks;
+
+#endif /* __GLOBALS_H__ */
diff --git a/conts/posix/fs0/include/init.h b/conts/posix/fs0/include/init.h
new file mode 100644
index 0000000..30b4104
--- /dev/null
+++ b/conts/posix/fs0/include/init.h
@@ -0,0 +1,7 @@
+#ifndef __INIT_H__
+#define __INIT_H__
+
+/* FS0 initialisation */
+int initialise(void);
+
+#endif /* __INIT_H__ */
diff --git a/conts/posix/fs0/include/lib/bit.h b/conts/posix/fs0/include/lib/bit.h
new file mode 100644
index 0000000..7d6f8a7
--- /dev/null
+++ b/conts/posix/fs0/include/lib/bit.h
@@ -0,0 +1,44 @@
+#ifndef __LIB_BIT_H__
+#define __LIB_BIT_H__
+
+#include
+
+unsigned int __clz(unsigned int bitvector);
+int find_and_set_first_free_bit(u32 *word, unsigned int lastbit);
+int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit,
+ int nbits);
+int check_and_clear_bit(u32 *word, int bit);
+int check_and_clear_contig_bits(u32 *word, int first, int nbits);
+
+int check_and_set_bit(u32 *word, int bit);
+
+/* Set */
+static inline void setbit(unsigned int *w, unsigned int flags)
+{
+ *w |= flags;
+}
+
+
+/* Clear */
+static inline void clrbit(unsigned int *w, unsigned int flags)
+{
+ *w &= ~flags;
+}
+
+/* Test */
+static inline int tstbit(unsigned int *w, unsigned int flags)
+{
+ return *w & flags;
+}
+
+/* Test and clear */
+static inline int tstclr(unsigned int *w, unsigned int flags)
+{
+ int res = tstbit(w, flags);
+
+ clrbit(w, flags);
+
+ return res;
+}
+
+#endif /* __LIB_BIT_H__ */
diff --git a/conts/posix/fs0/include/lib/idpool.h b/conts/posix/fs0/include/lib/idpool.h
new file mode 100644
index 0000000..2650e75
--- /dev/null
+++ b/conts/posix/fs0/include/lib/idpool.h
@@ -0,0 +1,29 @@
+#ifndef __MM0_IDPOOL_H__
+#define __MM0_IDPOOL_H__
+
+#include
+#include
+#include INC_GLUE(memory.h)
+#include
+
+struct id_pool {
+ int nwords;
+ u32 bitmap[];
+};
+
+/* Copy one id pool to another by calculating its size */
+static inline void id_pool_copy(struct id_pool *to, struct id_pool *from, int totalbits)
+{
+ int nwords = BITWISE_GETWORD(totalbits);
+
+ memcpy(to, from, nwords * SZ_WORD + sizeof(struct id_pool));
+}
+
+struct id_pool *id_pool_new_init(int mapsize);
+int id_new(struct id_pool *pool);
+int id_del(struct id_pool *pool, int id);
+int id_get(struct id_pool *pool, int id);
+int ids_new_contiguous(struct id_pool *pool, int numids);
+int ids_del_contiguous(struct id_pool *pool, int first, int numids);
+
+#endif /* __MM0_IDPOOL_H__ */
diff --git a/conts/posix/fs0/include/lib/malloc.h b/conts/posix/fs0/include/lib/malloc.h
new file mode 100644
index 0000000..37479ff
--- /dev/null
+++ b/conts/posix/fs0/include/lib/malloc.h
@@ -0,0 +1,19 @@
+#ifndef __PRIVATE_MALLOC_H__
+#define __PRIVATE_MALLOC_H__
+
+#include
+#include
+
+void *kmalloc(size_t size);
+void kfree(void *blk);
+
+static inline void *kzalloc(size_t size)
+{
+ void *buf = kmalloc(size);
+
+ memset(buf, 0, size);
+ return buf;
+}
+
+
+#endif /*__PRIVATE_MALLOC_H__ */
diff --git a/conts/posix/fs0/include/lib/pathstr.h b/conts/posix/fs0/include/lib/pathstr.h
new file mode 100644
index 0000000..724f870
--- /dev/null
+++ b/conts/posix/fs0/include/lib/pathstr.h
@@ -0,0 +1,9 @@
+#ifndef __LIB_PATHSTR_H__
+#define __LIB_PATHSTR_H__
+
+char *strreverse(char *str);
+char *splitpath_end(char **path, char sep);
+char *splitpath(char **str, char sep);
+
+
+#endif /* __LIB_PATHSTR_H__ */
diff --git a/conts/posix/fs0/include/lib/spinlock.h b/conts/posix/fs0/include/lib/spinlock.h
new file mode 100644
index 0000000..b3cc39c
--- /dev/null
+++ b/conts/posix/fs0/include/lib/spinlock.h
@@ -0,0 +1,15 @@
+/*
+ * Fake spinlock for future multi-threaded mm0
+ */
+#ifndef __MM0_SPINLOCK_H__
+#define __MM0_SPINLOCK_H__
+
+struct spinlock {
+ int lock;
+};
+
+static inline void spin_lock_init(struct spinlock *s) { }
+static inline void spin_lock(struct spinlock *s) { }
+static inline void spin_unlock(struct spinlock *s) { }
+
+#endif /* __MM0_SPINLOCK_H__ */
diff --git a/conts/posix/fs0/include/lib/vaddr.h b/conts/posix/fs0/include/lib/vaddr.h
new file mode 100644
index 0000000..d26d8af
--- /dev/null
+++ b/conts/posix/fs0/include/lib/vaddr.h
@@ -0,0 +1,17 @@
+/*
+ * Virtual address allocation pool (for shm)
+ *
+ * Copyright (C) 2007 Bahadir Balban
+ */
+#ifndef __VADDR_H__
+#define __VADDR_H__
+
+#include
+
+void vaddr_pool_init(struct id_pool *pool, unsigned long start,
+ unsigned long end);
+void *vaddr_new(struct id_pool *pool, int npages);
+int vaddr_del(struct id_pool *, void *vaddr, int npages);
+
+#endif /* __VADDR_H__ */
+
diff --git a/conts/posix/fs0/include/linker.lds b/conts/posix/fs0/include/linker.lds
new file mode 100644
index 0000000..90173fc
--- /dev/null
+++ b/conts/posix/fs0/include/linker.lds
@@ -0,0 +1,49 @@
+/*
+ * 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;
+physical_base = 0x8000;
+__stack = (0x20000000 - 0x1000 - 8); /* First page before env/args page */
+/* 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) { *(.text.head) *(.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); /* Align UTCB to page boundary */
+ _start_utcb = .;
+ *(.utcb)
+ _end_utcb = .;
+ . = ALIGN(4K);
+ _start_bdev = .;
+ *(.data.memfs)
+ _end_bdev = .;
+ *(.data)
+ }
+ .bss : AT (ADDR(.bss) - offset) { *(.bss) }
+
+ _end = .;
+}
diff --git a/conts/posix/fs0/include/memfs/file.h b/conts/posix/fs0/include/memfs/file.h
new file mode 100644
index 0000000..9679bee
--- /dev/null
+++ b/conts/posix/fs0/include/memfs/file.h
@@ -0,0 +1,7 @@
+#ifndef __MEMFS_FILE_H__
+#define __MEMFS_FILE_H__
+
+extern struct file_ops memfs_file_operations;
+extern struct dentry_ops memfs_dentry_operations;
+
+#endif /* __MEMFS_FILE_H__ */
diff --git a/conts/posix/fs0/include/memfs/memfs.h b/conts/posix/fs0/include/memfs/memfs.h
new file mode 100644
index 0000000..6b17d16
--- /dev/null
+++ b/conts/posix/fs0/include/memfs/memfs.h
@@ -0,0 +1,97 @@
+/*
+ * The disk layout of our simple unix-like filesystem.
+ *
+ * Copyright (C) 2007, 2008 Bahadir Balban
+ */
+
+#ifndef __MEMFS_LAYOUT_H__
+#define __MEMFS_LAYOUT_H__
+
+#include
+#include
+#include
+#include
+#include INC_GLUE(memory.h)
+#include
+#include
+
+/*
+ *
+ * Filesystem layout:
+ *
+ * |---------------|
+ * | Superblock |
+ * |---------------|
+ *
+ * Superblock layout:
+ *
+ * |---------------|
+ * | inode cache |
+ * |---------------|
+ * | dentry cache |
+ * |---------------|
+ * | block cache |
+ * |---------------|
+ *
+ */
+
+/*
+ * These fixed filesystem limits make it much easier to implement
+ * filesystem space allocation.
+ */
+#define MEMFS_TOTAL_SIZE SZ_4MB
+#define MEMFS_TOTAL_INODES 128
+#define MEMFS_TOTAL_BLOCKS 2000
+#define MEMFS_FMAX_BLOCKS 40
+#define MEMFS_BLOCK_SIZE PAGE_SIZE
+#define MEMFS_MAGIC 0xB
+#define MEMFS_NAME "memfs"
+#define MEMFS_NAME_SIZE 8
+
+struct memfs_inode {
+ u32 inum; /* Inode number */
+ u32 mode; /* File permissions */
+ u32 owner; /* File owner */
+ u64 atime; /* Last access time */
+ u64 mtime; /* Last content modification */
+ u64 ctime; /* Last inode modification */
+ u64 size; /* Size of contents */
+ void *block[MEMFS_FMAX_BLOCKS]; /* Number of blocks */
+};
+
+struct memfs_superblock {
+ u32 magic; /* Filesystem magic number */
+ char name[8];
+ u32 blocksize; /* Filesystem block size */
+ u64 fmaxblocks; /* Maximum number of blocks per file */
+ u64 fssize; /* Total size of filesystem */
+ unsigned long root_vnum; /* The root vnum of this superblock */
+ struct link inode_cache_list; /* Chain of alloc caches */
+ struct link block_cache_list; /* Chain of alloc caches */
+ struct id_pool *ipool; /* Index pool for inodes */
+ struct id_pool *bpool; /* Index pool for blocks */
+ struct memfs_inode *inode[MEMFS_TOTAL_INODES]; /* Table of inodes */
+ void *block[MEMFS_TOTAL_BLOCKS]; /* Table of fs blocks */
+} __attribute__ ((__packed__));
+
+#define MEMFS_DNAME_MAX 32
+struct memfs_dentry {
+ u32 inum; /* Inode number */
+ u32 offset; /* Dentry offset in its buffer */
+ u16 rlength; /* Record length */
+ u8 name[MEMFS_DNAME_MAX]; /* Name string */
+};
+
+extern struct vnode_ops memfs_vnode_operations;
+extern struct superblock_ops memfs_superblock_operations;
+extern struct file_ops memfs_file_operations;
+
+int memfs_format_filesystem(void *buffer);
+struct memfs_inode *memfs_create_inode(struct memfs_superblock *sb);
+void memfs_register_fstype(struct link *);
+struct superblock *memfs_get_superblock(void *block);
+int memfs_generate_superblock(void *block);
+
+void *memfs_alloc_block(struct memfs_superblock *sb);
+int memfs_free_block(struct memfs_superblock *sb, void *block);
+#endif /* __MEMFS_LAYOUT_H__ */
diff --git a/conts/posix/fs0/include/memfs/vnode.h b/conts/posix/fs0/include/memfs/vnode.h
new file mode 100644
index 0000000..38e3080
--- /dev/null
+++ b/conts/posix/fs0/include/memfs/vnode.h
@@ -0,0 +1,7 @@
+#ifndef __MEMFS_VNODE_H__
+#define __MEMFS_VNODE_H__
+
+#include
+
+
+#endif /* __MEMFS_VNODE_H__ */
diff --git a/conts/posix/fs0/include/path.h b/conts/posix/fs0/include/path.h
new file mode 100644
index 0000000..cfde50e
--- /dev/null
+++ b/conts/posix/fs0/include/path.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 Bahadir Balban
+ *
+ * Path lookup related information
+ */
+#ifndef __PATH_H__
+#define __PATH_H__
+
+#include
+#include
+
+/*
+ * FIXME:
+ * These ought to be strings and split/comparison functions should
+ * always use strings because formats like UTF-8 wouldn't work.
+ */
+#define VFS_CHAR_SEP '/'
+#define VFS_STR_ROOTDIR "/"
+#define VFS_STR_PARDIR ".."
+#define VFS_STR_CURDIR "."
+#define VFS_STR_XATDIR "...."
+
+struct pathdata {
+ struct link list;
+ struct vnode *vstart;
+};
+
+struct pathcomp {
+ struct link list;
+ const char *str;
+};
+
+struct pathdata *pathdata_parse(const char *pathname, char *pathbuf,
+ struct tcb *task);
+void pathdata_destroy(struct pathdata *p);
+
+/* Destructive, i.e. unlinks those components from list */
+const char *pathdata_next_component(struct pathdata *pdata);
+const char *pathdata_last_component(struct pathdata *pdata);
+
+#endif /* __PATH_H__ */
diff --git a/conts/posix/fs0/include/stat.h b/conts/posix/fs0/include/stat.h
new file mode 100644
index 0000000..ee7225e
--- /dev/null
+++ b/conts/posix/fs0/include/stat.h
@@ -0,0 +1,82 @@
+#ifndef __FS0_STAT_H__
+#define __FS0_STAT_H__
+
+/* Posix definitions for file mode flags (covers type and access permissions) */
+#define S_IFMT 00170000
+#define S_IFSOCK 0140000
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFBLK 0060000
+#define S_IFDIR 0040000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_ISUID 0004000
+#define S_ISGID 0002000
+#define S_ISVTX 0001000
+
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+
+#define S_IRWXU 00700
+#define S_IRUSR 00400
+#define S_IWUSR 00200
+#define S_IXUSR 00100
+
+#define S_IRWXG 00070
+#define S_IRGRP 00040
+#define S_IWGRP 00020
+#define S_IXGRP 00010
+
+#define S_IRWXO 00007
+#define S_IROTH 00004
+#define S_IWOTH 00002
+#define S_IXOTH 00001
+
+#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
+#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
+#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
+#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
+#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
+
+#define O_ACCMODE 00000003
+#define O_RDONLY 00000000
+#define O_WRONLY 00000001
+#define O_RDWR 00000002
+#define O_CREAT 00000100
+#define O_EXCL 00000200
+#define O_NOCTTY 00000400
+#define O_TRUNC 00001000
+#define O_APPEND 00002000
+#define O_NONBLOCK 00004000
+#define O_SYNC 00010000
+#define FASYNC 00020000
+#define O_DIRECT 00040000
+#define O_LARGEFILE 00100000
+#define O_DIRECTORY 00200000
+#define O_NOFOLLOW 00400000
+#define O_NOATIME 01000000
+#define O_NDELAY O_NONBLOCK
+
+/*
+ * Internal codezero-specific stat structure.
+ * This is converted to posix stat in userspace
+ */
+struct kstat {
+ u64 vnum;
+ u32 mode;
+ int links;
+ u16 uid;
+ u16 gid;
+ u64 size;
+ int blksize;
+ u64 atime;
+ u64 mtime;
+ u64 ctime;
+};
+
+#endif /* __FS0_STAT_H__ */
diff --git a/conts/posix/fs0/include/syscalls.h b/conts/posix/fs0/include/syscalls.h
new file mode 100644
index 0000000..b10b892
--- /dev/null
+++ b/conts/posix/fs0/include/syscalls.h
@@ -0,0 +1,35 @@
+/*
+ * System call function signatures.
+ *
+ * Copyright (C) 2007, 2008 Bahadir Balban
+ */
+#ifndef __FS0_SYSCALLS_H__
+#define __FS0_SYSCALLS_H__
+
+#include
+
+/* Posix calls */
+int sys_open(struct tcb *sender, const char *pathname, int flags, u32 mode);
+int sys_readdir(struct tcb *sender, int fd, void *buf, int count);
+int sys_mkdir(struct tcb *sender, const char *pathname, unsigned int mode);
+int sys_chdir(struct tcb *sender, const char *pathname);
+
+/* Calls from pager that completes a posix call */
+int pager_open_bypath(struct tcb *pager, char *pathname);
+int pager_sys_open(struct tcb *sender, l4id_t opener, int fd);
+int pager_sys_read(struct tcb *sender, unsigned long vnum, unsigned long f_offset,
+ unsigned long npages, void *pagebuf);
+
+int pager_sys_write(struct tcb *sender, unsigned long vnum, unsigned long f_offset,
+ unsigned long npages, void *pagebuf);
+
+int pager_sys_close(struct tcb *sender, l4id_t closer, int fd);
+int pager_update_stats(struct tcb *sender, unsigned long vnum,
+ unsigned long newsize);
+
+int pager_notify_fork(struct tcb *sender, l4id_t parentid,
+ l4id_t childid, unsigned long utcb_address,
+ unsigned int flags);
+
+int pager_notify_exit(struct tcb *sender, l4id_t tid);
+#endif /* __FS0_SYSCALLS_H__ */
diff --git a/conts/posix/fs0/include/task.h b/conts/posix/fs0/include/task.h
new file mode 100644
index 0000000..7908755
--- /dev/null
+++ b/conts/posix/fs0/include/task.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 Bahadir Balban
+ */
+#ifndef __FS0_TASK_H__
+#define __FS0_TASK_H__
+
+#include
+#include
+#include
+
+#define __TASKNAME__ __VFSNAME__
+
+#define TCB_NO_SHARING 0
+#define TCB_SHARED_VM (1 << 0)
+#define TCB_SHARED_FILES (1 << 1)
+#define TCB_SHARED_FS (1 << 2)
+
+#define TASK_FILES_MAX 32
+
+struct task_fd_head {
+ int fd[TASK_FILES_MAX];
+ struct id_pool *fdpool;
+ int tcb_refs;
+};
+
+struct task_fs_data {
+ struct vnode *curdir;
+ struct vnode *rootdir;
+ int tcb_refs;
+};
+
+/* Thread control block, fs0 portion */
+struct tcb {
+ l4id_t tid;
+ struct link list;
+ unsigned long shpage_address;
+ struct task_fd_head *files;
+ struct task_fs_data *fs_data;
+};
+
+/* Structures used when receiving new task info from pager */
+struct task_data {
+ unsigned long tid;
+ unsigned long shpage_address;
+};
+
+struct task_data_head {
+ unsigned long total;
+ struct task_data tdata[];
+};
+
+struct tcb *find_task(int tid);
+int init_task_data(void);
+
+#endif /* __FS0_TASK_H__ */
diff --git a/conts/posix/fs0/include/vfs.h b/conts/posix/fs0/include/vfs.h
new file mode 100644
index 0000000..5d9b5a8
--- /dev/null
+++ b/conts/posix/fs0/include/vfs.h
@@ -0,0 +1,90 @@
+#ifndef __VFS_H__
+#define __VFS_H__
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+extern struct link vnode_cache;
+extern struct link dentry_cache;
+
+/*
+ * This is a temporary origacement for page cache support provided by mm0.
+ * Normally mm0 tracks all vnode pages, but this is used to track pages in
+ * directory vnodes, which are normally never mapped by tasks.
+ */
+static inline void *vfs_alloc_dirpage(struct vnode *v)
+{
+ /*
+ * Urgh, we allocate from the block cache of memfs to store generic vfs directory
+ * pages. This is currently the quickest we can allocate page-aligned memory.
+ */
+ return memfs_alloc_block(v->sb->fs_super);
+}
+
+static inline void vfs_free_dirpage(struct vnode *v, void *block)
+{
+ memfs_free_block(v->sb->fs_super, block);
+}
+
+static inline struct dentry *vfs_alloc_dentry(void)
+{
+ struct dentry *d = kzalloc(sizeof(struct dentry));
+
+ link_init(&d->child);
+ link_init(&d->children);
+ link_init(&d->vref);
+ link_init(&d->cache_list);
+
+ return d;
+}
+
+static inline void vfs_free_dentry(struct dentry *d)
+{
+ return kfree(d);
+}
+
+static inline struct vnode *vfs_alloc_vnode(void)
+{
+ struct vnode *v = kzalloc(sizeof(struct vnode));
+
+ link_init(&v->dentries);
+ link_init(&v->cache_list);
+
+ return v;
+}
+
+static inline void vfs_free_vnode(struct vnode *v)
+{
+ BUG(); /* Are the dentries freed ??? */
+ list_remove(&v->cache_list);
+ kfree(v);
+}
+
+static inline struct superblock *vfs_alloc_superblock(void)
+{
+ struct superblock *sb = kmalloc(sizeof(struct superblock));
+ link_init(&sb->list);
+
+ return sb;
+}
+
+struct vfs_mountpoint {
+ struct superblock *sb; /* The superblock of mounted filesystem */
+ struct vnode *pivot; /* The dentry upon which we mount */
+};
+
+extern struct vfs_mountpoint vfs_root;
+
+int vfs_mount_root(struct superblock *sb);
+struct vnode *generic_vnode_lookup(struct vnode *thisnode, struct pathdata *p,
+ const char *component);
+struct vnode *vfs_lookup_bypath(struct pathdata *p);
+struct vnode *vfs_lookup_byvnum(struct superblock *sb, unsigned long vnum);
+
+#endif /* __VFS_H__ */
diff --git a/conts/posix/fs0/main.c b/conts/posix/fs0/main.c
new file mode 100644
index 0000000..b5b672b
--- /dev/null
+++ b/conts/posix/fs0/main.c
@@ -0,0 +1,148 @@
+/*
+ * FS0. Filesystem implementation
+ *
+ * Copyright (C) 2007 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * TODO:
+ * - Have a dentry cache searchable by name
+ * - Have a vnode cache searchable by vnum (and name?)
+ * - fs-specific readdir would read contents by page range, and add vnodes/dentries
+ * to their caches, while populating the directory vnode being read.
+ * - Have 2 vfs_lookup() flavors, one that searches a path, one that searches a vnum.
+ * - dirbuf is either allocated by low-level readdir, or else by a higher level, i.e.
+ * either high-level vfs code, or the mm0 page cache.
+ * - readdir provides a posix-compliant dirent structure list in dirbuf.
+ * - memfs dentries should be identical to posix struct dirents.
+ *
+ * ALL DONE!!! But untested.
+ *
+ * - Add mkdir
+ * - Add create
+ * - Add read/write -> This will need page cache and mm0 involvement.
+ *
+ * Done those, too. but untested.
+ */
+
+/* Synchronise with pager via a `wait' tagged ipc with destination as pager */
+void wait_pager(l4id_t partner)
+{
+ l4_send(partner, L4_IPC_TAG_SYNC);
+ // printf("%s: Pager synced with us.\n", __TASKNAME__);
+}
+
+void handle_fs_requests(void)
+{
+ u32 mr[MR_UNUSED_TOTAL];
+ l4id_t senderid;
+ struct tcb *sender;
+ int ret;
+ u32 tag;
+
+ if ((ret = l4_receive(L4_ANYTHREAD)) < 0) {
+ printf("%s: %s: IPC Error: %d. Quitting...\n", __TASKNAME__,
+ __FUNCTION__, ret);
+ BUG();
+ }
+
+ /* Read conventional ipc data */
+ tag = l4_get_tag();
+ senderid = l4_get_sender();
+
+ if (!(sender = find_task(senderid))) {
+ l4_ipc_return(-ESRCH);
+ return;
+ }
+
+ /* Read mrs not used by syslib */
+ for (int i = 0; i < MR_UNUSED_TOTAL; i++)
+ mr[i] = read_mr(MR_UNUSED_START + i);
+
+ /* FIXME: Fix all these syscalls to read any buffer data from the caller task's utcb.
+ * Make sure to return -EINVAL if data is not valid. */
+ switch(tag) {
+ case L4_IPC_TAG_SYNC:
+ printf("%s: Synced with waiting thread.\n", __TASKNAME__);
+ return; /* No origy for this tag */
+ case L4_IPC_TAG_OPEN:
+ ret = sys_open(sender, (void *)mr[0], (int)mr[1], (unsigned int)mr[2]);
+ break;
+ case L4_IPC_TAG_MKDIR:
+ ret = sys_mkdir(sender, (const char *)mr[0], (unsigned int)mr[1]);
+ break;
+ case L4_IPC_TAG_CHDIR:
+ ret = sys_chdir(sender, (const char *)mr[0]);
+ break;
+ case L4_IPC_TAG_READDIR:
+ ret = sys_readdir(sender, (int)mr[0], (void *)mr[1], (int)mr[2]);
+ break;
+ case L4_IPC_TAG_PAGER_READ:
+ ret = pager_sys_read(sender, (unsigned long)mr[0], (unsigned long)mr[1],
+ (unsigned long)mr[2], (void *)mr[3]);
+ break;
+ case L4_IPC_TAG_PAGER_OPEN:
+ ret = pager_sys_open(sender, (l4id_t)mr[0], (int)mr[1]);
+ break;
+ case L4_IPC_TAG_PAGER_OPEN_BYPATH:
+ ret = pager_open_bypath(sender, (char *)mr[0]);
+ break;
+ case L4_IPC_TAG_PAGER_WRITE:
+ ret = pager_sys_write(sender, (unsigned long)mr[0], (unsigned long)mr[1],
+ (unsigned long)mr[2], (void *)mr[3]);
+ break;
+ case L4_IPC_TAG_PAGER_CLOSE:
+ ret = pager_sys_close(sender, (l4id_t)mr[0], (int)mr[1]);
+ break;
+ case L4_IPC_TAG_PAGER_UPDATE_STATS:
+ ret = pager_update_stats(sender, (unsigned long)mr[0],
+ (unsigned long)mr[1]);
+ break;
+ case L4_IPC_TAG_NOTIFY_FORK:
+ ret = pager_notify_fork(sender, (l4id_t)mr[0], (l4id_t)mr[1],
+ (unsigned long)mr[2], (unsigned int)mr[3]);
+ break;
+ case L4_IPC_TAG_NOTIFY_EXIT:
+ ret = pager_notify_exit(sender, (l4id_t)mr[0]);
+ break;
+
+ default:
+ printf("%s: Unrecognised ipc tag (%d) "
+ "received from tid: %d. Ignoring.\n", __TASKNAME__,
+ mr[MR_TAG], senderid);
+ }
+
+ /* Reply */
+ if ((ret = l4_ipc_return(ret)) < 0) {
+ printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, ret);
+ BUG();
+ }
+}
+
+void main(void)
+{
+ printf("\n%s: Started with thread id %d\n", __TASKNAME__, self_tid());
+
+ initialise();
+
+ wait_pager(PAGER_TID);
+
+ printf("%s: VFS service initialized. Listening requests.\n", __TASKNAME__);
+ while (1) {
+ handle_fs_requests();
+ }
+}
+
diff --git a/conts/posix/fs0/src/bdev.c b/conts/posix/fs0/src/bdev.c
new file mode 100644
index 0000000..1f69162
--- /dev/null
+++ b/conts/posix/fs0/src/bdev.c
@@ -0,0 +1,15 @@
+/*
+ * This is just to allocate some memory as a block device.
+ */
+#include
+#include
+
+extern char _start_bdev[];
+extern char _end_bdev[];
+
+__attribute__((section(".data.memfs"))) char blockdevice[MEMFS_TOTAL_SIZE];
+
+void *vfs_rootdev_open(void)
+{
+ return (void *)_start_bdev;
+}
diff --git a/conts/posix/fs0/src/bootfs/bootfs.c b/conts/posix/fs0/src/bootfs/bootfs.c
new file mode 100644
index 0000000..1b3fdcb
--- /dev/null
+++ b/conts/posix/fs0/src/bootfs/bootfs.c
@@ -0,0 +1,147 @@
+/*
+ * A pseudo-filesystem for reading the in-memory
+ * server tasks loaded from the initial elf executable.
+ *
+ * Copyright (C) 2007, 2008 Bahadir Balban
+ */
+#include
+#include
+#include
+
+struct dentry *bootfs_dentry_lookup(struct dentry *d, char *dname)
+{
+ struct dentry *this;
+
+ list_foreach_struct(this, child, &d->children) {
+ if (this->compare(this, dname))
+ return this;
+ }
+ return 0;
+}
+
+struct dentry *path_lookup(struct superblock *sb, char *pathstr)
+{
+ char *dname;
+ char *splitpath;
+ struct dentry *this, *next;
+
+ /* First dentry is root */
+ this = sb->root;
+
+ /* Get next path component from path string */
+ dname = path_next_dentry_name(pathstr);
+
+ if (!this->compare(dname))
+ return;
+
+ while(!(dname = path_next_dentry_name(pathstr))) {
+ if ((d = this->lookup(this, dname)))
+ return 0;
+ }
+}
+
+/*
+ * This creates a pseudo-filesystem tree from the loaded
+ * server elf images whose information is available from
+ * initdata.
+ */
+void bootfs_populate(struct initdata *initdata, struct superblock *sb)
+{
+ struct bootdesc *bd = initdata->bootdesc;
+ struct svc_image *img;
+ struct dentry *d;
+ struct vnode *v;
+ struct file *f;
+
+ for (int i = 0; i < bd->total_images; i++) {
+ img = &bd->images[i];
+
+ d = malloc(sizeof(struct dentry));
+ v = malloc(sizeof(struct vnode));
+ f = malloc(sizeof(struct file));
+
+ /* Initialise dentry for image */
+ d->refcnt = 0;
+ d->vnode = v;
+ d->parent = sb->root;
+ strncpy(d->name, img->name, VFS_DENTRY_NAME_MAX);
+ link_init(&d->child);
+ link_init(&d->children);
+ list_insert(&d->child, &sb->root->children);
+
+ /* Initialise vnode for image */
+ v->refcnt = 0;
+ v->id = img->phys_start;
+ v->size = img->phys_end - img->phys_start;
+ link_init(&v->dirents);
+ list_insert(&d->v_ref, &v->dirents);
+
+ /* Initialise file struct for image */
+ f->refcnt = 0;
+ f->dentry = d;
+
+ img_d++;
+ img_vn++;
+ img_f++;
+ }
+}
+
+void bootfs_init_root(struct dentry *r)
+{
+ struct vnode *v = r->vnode;
+
+ /* Initialise dentry for rootdir */
+ r->refcnt = 0;
+ strcpy(r->name, "");
+ link_init(&r->child);
+ link_init(&r->children);
+ link_init(&r->vref);
+ r->parent = r;
+
+ /* Initialise vnode for rootdir */
+ v->id = 0;
+ v->refcnt = 0;
+ link_init(&v->dirents);
+ link_init(&v->state_list);
+ list_insert(&r->vref, &v->dirents);
+ v->size = 0;
+}
+
+struct superblock *bootfs_init_sb(struct superblock *sb)
+{
+ sb->root = malloc(sizeof(struct dentry));
+ sb->root->vnode = malloc(sizeof(struct vnode));
+
+ bootfs_init_root(&sb->root);
+
+ return sb;
+}
+
+struct superblock bootfs_sb = {
+ .fs = bootfs_type,
+ .ops = {
+ .read_sb = bootfs_read_sb,
+ .write_sb = bootfs_write_sb,
+ .read_vnode = bootfs_read_vnode,
+ .write_vnode = bootfs_write_vnode,
+ },
+};
+
+struct superblock *bootfs_get_sb(void)
+{
+ bootfs_init_sb(&bootfs_sb);
+ return &bootfs_sb;
+}
+
+struct file_system_type bootfs_type = {
+ .name = "bootfs",
+ .magic = 0,
+ .get_sb = bootfs_get_sb,
+};
+
+void init_bootfs()
+{
+ bootfs_init_sb(&bootfs_sb);
+
+ bootfs_populate(&bootfs_sb);
+}
diff --git a/conts/posix/fs0/src/c0fs/c0fs.c b/conts/posix/fs0/src/c0fs/c0fs.c
new file mode 100644
index 0000000..d1146b2
--- /dev/null
+++ b/conts/posix/fs0/src/c0fs/c0fs.c
@@ -0,0 +1,29 @@
+/*
+ * A basic unix-like read/writeable filesystem for Codezero.
+ *
+ * Copyright (C) 2007, 2008 Bahadir Balban
+ */
+#include
+#include
+
+void sfs_read_sb(struct superblock *sb)
+{
+
+}
+
+static void simplefs_alloc_vnode(struct vnode *)
+{
+
+}
+
+struct file_system_type sfs_type = {
+ .name = "c0fs",
+ .magic = 1,
+ .flags = 0,
+};
+
+/* Registers sfs as an available filesystem type */
+void sfs_register_fstype(struct link *fslist)
+{
+ list_insert(&sfs_type.list, fslist);
+}
diff --git a/conts/posix/fs0/src/c0fs/c0fs.h b/conts/posix/fs0/src/c0fs/c0fs.h
new file mode 100644
index 0000000..da91f15
--- /dev/null
+++ b/conts/posix/fs0/src/c0fs/c0fs.h
@@ -0,0 +1,113 @@
+/*
+ * The disk layout of our simple unix-like filesystem.
+ *
+ * Copyright (C) 2007, 2008 Bahadir Balban
+ */
+
+#ifndef __C0FS_LAYOUT_H__
+#define __C0FS_LAYOUT_H__
+
+#include
+#include
+#include
+#include
+#include INC_GLUE(memory.h)
+
+/*
+ *
+ * Filesystem layout:
+ *
+ * |---------------|
+ * | Group 0 |
+ * |---------------|
+ * | Group 1 |
+ * |---------------|
+ * | ... |
+ * |---------------|
+ * | Group n |
+ * |---------------|
+ *
+ *
+ * Group layout:
+ *
+ * |---------------|
+ * | Superblock |
+ * |---------------|
+ * | Inode table |
+ * |---------------|
+ * | Data blocks |
+ * |---------------|
+ *
+ * or
+ *
+ * |---------------|
+ * | Data blocks |
+ * |---------------|
+ *
+ */
+
+#define BLOCK_SIZE PAGE_SIZE
+#define BLOCK_BITS PAGE_BITS
+#define GROUP_SIZE SZ_8MB
+#define INODE_TABLE_SIZE ((GROUP_SIZE / BLOCK_SIZE) / 2)
+#define INODE_BITMAP_SIZE (INODE_TABLE_SIZE >> 5)
+
+
+struct sfs_superblock {
+ u32 magic; /* Filesystem magic number */
+ u64 fssize; /* Total size of filesystem */
+ u32 total; /* To */
+ u32 groupmap[]; /* Bitmap of all fs groups */
+};
+
+struct sfs_group_table {
+ u32 total;
+ u32 free;
+ u32 groupmap[];
+};
+
+struct sfs_inode_table {
+ u32 total;
+ u32 free;
+ u32 inodemap[INODE_BITMAP_SIZE];
+ struct sfs_inode inode[INODE_TABLE_SIZE];
+};
+
+/*
+ * The purpose of an inode:
+ *
+ * 1) Uniquely identify a file or a directory.
+ * 2) Keep file/directory metadata.
+ * 3) Provide access means to file blocks/directory contents.
+ */
+#define INODE_DIRECT_BLOCKS 5
+struct sfs_inode_blocks {
+ int szidx; /* Direct array index size */
+ unsigned long indirect;
+ unsigned long indirect2;
+ unsigned long indirect3;
+ unsigned long direct[];
+};
+
+struct sfs_inode {
+ u32 unum; /* Unit number this inode is in */
+ u32 inum; /* Inode number */
+ u32 mode; /* File permissions */
+ u32 owner; /* File owner */
+ u64 atime; /* Last access time */
+ u64 mtime; /* Last content modification */
+ u64 ctime; /* Last inode modification */
+ u64 size; /* Size of contents */
+ struct sfs_inode_blocks blocks;
+} __attribute__ ((__packed__));
+
+struct sfs_dentry {
+ u32 inum; /* Inode number */
+ u32 nlength; /* Name length */
+ u8 name[]; /* Name string */
+} __attribute__ ((__packed__));
+
+
+void sfs_register_type(struct link *);
+
+#endif /* __C0FS_LAYOUT_H__ */
diff --git a/conts/posix/fs0/src/crt0.S b/conts/posix/fs0/src/crt0.S
new file mode 100644
index 0000000..9bcb3a8
--- /dev/null
+++ b/conts/posix/fs0/src/crt0.S
@@ -0,0 +1,94 @@
+/*
+ * Australian Public Licence B (OZPLB)
+ *
+ * Version 1-0
+ *
+ * Copyright (c) 2004 National ICT Australia
+ *
+ * All rights reserved.
+ *
+ * Developed by: Embedded, Real-time and Operating Systems Program (ERTOS)
+ * National ICT Australia
+ * http://www.ertos.nicta.com.au
+ *
+ * Permission is granted by National ICT Australia, free of charge, to
+ * any person obtaining a copy of this software and any associated
+ * documentation files (the "Software") to deal with the Software without
+ * restriction, including (without limitation) the rights to use, copy,
+ * modify, adapt, merge, publish, distribute, communicate to the public,
+ * sublicense, and/or sell, lend or rent out copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimers.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimers in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * * Neither the name of National ICT Australia, nor the names of its
+ * contributors, may be used to endorse or promote products derived
+ * from this Software without specific prior written permission.
+ *
+ * EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
+ * PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS", AND
+ * NATIONAL ICT AUSTRALIA AND ITS CONTRIBUTORS MAKE NO REPRESENTATIONS,
+ * WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS
+ * REGARDING THE CONTENTS OR ACCURACY OF THE SOFTWARE, OR OF TITLE,
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT,
+ * THE ABSENCE OF LATENT OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF
+ * ERRORS, WHETHER OR NOT DISCOVERABLE.
+ *
+ * TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
+ * NATIONAL ICT AUSTRALIA OR ITS CONTRIBUTORS BE LIABLE ON ANY LEGAL
+ * THEORY (INCLUDING, WITHOUT LIMITATION, IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHERWISE) FOR ANY CLAIM, LOSS, DAMAGES OR OTHER
+ * LIABILITY, INCLUDING (WITHOUT LIMITATION) LOSS OF PRODUCTION OR
+ * OPERATION TIME, LOSS, DAMAGE OR CORRUPTION OF DATA OR RECORDS; OR LOSS
+ * OF ANTICIPATED SAVINGS, OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR
+ * OTHER ECONOMIC LOSS; OR ANY SPECIAL, INCIDENTAL, INDIRECT,
+ * CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES, ARISING OUT OF OR IN
+ * CONNECTION WITH THIS LICENCE, THE SOFTWARE OR THE USE OF OR OTHER
+ * DEALINGS WITH THE SOFTWARE, EVEN IF NATIONAL ICT AUSTRALIA OR ITS
+ * CONTRIBUTORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH CLAIM, LOSS,
+ * DAMAGES OR OTHER LIABILITY.
+ *
+ * If applicable legislation implies representations, warranties, or
+ * conditions, or imposes obligations or liability on National ICT
+ * Australia or one of its contributors in respect of the Software that
+ * cannot be wholly or partly excluded, restricted or modified, the
+ * liability of National ICT Australia or the contributor is limited, to
+ * the full extent permitted by the applicable legislation, at its
+ * option, to:
+ * a. in the case of goods, any one or more of the following:
+ * i. the replacement of the goods or the supply of equivalent goods;
+ * ii. the repair of the goods;
+ * iii. the payment of the cost of replacing the goods or of acquiring
+ * equivalent goods;
+ * iv. the payment of the cost of having the goods repaired; or
+ * b. in the case of services:
+ * i. the supplying of the services again; or
+ * ii. the payment of the cost of having the services supplied again.
+ *
+ * The construction, validity and performance of this licence is governed
+ * by the laws in force in New South Wales, Australia.
+ */
+
+#ifdef __thumb__
+#define bl blx
+#endif
+
+ .section .text.head
+ .code 32
+ .global _start;
+ .align;
+_start:
+ ldr sp, =__stack
+ bl platform_init
+ bl __container_init
+1:
+ b 1b
+
diff --git a/conts/posix/fs0/src/file.c b/conts/posix/fs0/src/file.c
new file mode 100644
index 0000000..2bfd6fe
--- /dev/null
+++ b/conts/posix/fs0/src/file.c
@@ -0,0 +1,25 @@
+/*
+ * File content tracking.
+ *
+ * Copyright (C) 2008 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include INC_GLUE(memory.h)
+#include
+
+/*
+ * This reads contents of a file in pages, calling the fs-specific file read function to read-in
+ * those pages' contents.
+ *
+ * Normally this is ought to be called by mm0 when a file's pages cannot be found in the page
+ * cache.
+ */
+int generic_file_read(struct vnode *v, unsigned long pfn, unsigned long npages, void *page_buf)
+{
+ BUG_ON(!is_page_aligned(page_buf));
+
+ return v->fops.read(v, pfn, npages, page_buf);
+}
diff --git a/conts/posix/fs0/src/init.c b/conts/posix/fs0/src/init.c
new file mode 100644
index 0000000..84ff20c
--- /dev/null
+++ b/conts/posix/fs0/src/init.c
@@ -0,0 +1,91 @@
+/*
+ * FS0 Initialisation.
+ *
+ * Copyright (C) 2007 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct link fs_type_list;
+
+struct superblock *vfs_probe_filesystems(void *block)
+{
+ struct file_system_type *fstype;
+ struct superblock *sb;
+
+ list_foreach_struct(fstype, &fs_type_list, list) {
+ /* Does the superblock match for this fs type? */
+ if ((sb = fstype->ops.get_superblock(block))) {
+ /*
+ * Add this to the list of superblocks this
+ * fs already has.
+ */
+ list_insert(&sb->list, &fstype->sblist);
+ return sb;
+ }
+ }
+
+ return PTR_ERR(-ENODEV);
+}
+
+/*
+ * Registers each available filesystem so that these can be
+ * used when probing superblocks on block devices.
+ */
+void vfs_register_filesystems(void)
+{
+ /* Initialise fstype list */
+ link_init(&fs_type_list);
+
+ /* Call per-fs registration functions */
+ memfs_register_fstype(&fs_type_list);
+}
+
+/*
+ * Filesystem initialisation.
+ */
+int initialise(void)
+{
+ void *rootdev_blocks;
+ struct superblock *root_sb;
+
+ /* Get standard init data from microkernel */
+ // request_initdata(&initdata);
+
+ /* Register compiled-in filesystems with vfs core. */
+ vfs_register_filesystems();
+
+ /* Get a pointer to first block of root block device */
+ rootdev_blocks = vfs_rootdev_open();
+
+ /*
+ * Since the *only* filesystem we have is a temporary memory
+ * filesystem, we create it on the root device first.
+ */
+ memfs_format_filesystem(rootdev_blocks);
+
+ /* Search for a filesystem on the root device */
+ BUG_ON(IS_ERR(root_sb = vfs_probe_filesystems(rootdev_blocks)));
+
+ /* Mount the filesystem on the root device */
+ vfs_mount_root(root_sb);
+
+ printf("%s: Mounted memfs root filesystem.\n", __TASKNAME__);
+
+ /* Learn about what tasks are running */
+ init_task_data();
+
+ /*
+ * Initialisation is done. From here on, we can start
+ * serving filesystem requests.
+ */
+ return 0;
+}
+
diff --git a/conts/posix/fs0/src/lib/bit.c b/conts/posix/fs0/src/lib/bit.c
new file mode 100644
index 0000000..7b1dee4
--- /dev/null
+++ b/conts/posix/fs0/src/lib/bit.c
@@ -0,0 +1,111 @@
+/*
+ * Bit manipulation functions.
+ *
+ * Copyright (C) 2007 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include INC_GLUE(memory.h)
+
+/* Emulation of ARM's CLZ (count leading zeroes) instruction */
+unsigned int __clz(unsigned int bitvector)
+{
+ unsigned int x = 0;
+ while((!(bitvector & ((unsigned)1 << 31))) && (x < 32)) {
+ bitvector <<= 1;
+ x++;
+ }
+ return x;
+}
+
+int find_and_set_first_free_bit(u32 *word, unsigned int limit)
+{
+ int success = 0;
+ int i;
+
+ for(i = 0; i < limit; i++) {
+ /* Find first unset bit */
+ if (!(word[BITWISE_GETWORD(i)] & BITWISE_GETBIT(i))) {
+ /* Set it */
+ word[BITWISE_GETWORD(i)] |= BITWISE_GETBIT(i);
+ success = 1;
+ break;
+ }
+ }
+ /* Return bit just set */
+ if (success)
+ return i;
+ else
+ return -1;
+}
+
+int find_and_set_first_free_contig_bits(u32 *word, unsigned int limit,
+ int nbits)
+{
+ int i = 0, first = 0, last = 0, found = 0;
+
+ /* Can't allocate more than the limit */
+ if (nbits > limit)
+ return -1;
+
+ /* This is a state machine that checks n contiguous free bits. */
+ while (i + nbits < limit) {
+ first = i;
+ last = i;
+ while (!(word[BITWISE_GETWORD(last)] & BITWISE_GETBIT(last))) {
+ last++;
+ i++;
+ if (last == first + nbits) {
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ break;
+ i++;
+ }
+
+ /* If found, set the bits */
+ if (found) {
+ for (int x = first; x < first + nbits; x++)
+ word[BITWISE_GETWORD(x)] |= BITWISE_GETBIT(x);
+ return first;
+ } else
+ return -1;
+}
+
+int check_and_clear_bit(u32 *word, int bit)
+{
+ /* Check that bit was set */
+ if (word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit)) {
+ word[BITWISE_GETWORD(bit)] &= ~BITWISE_GETBIT(bit);
+ return 0;
+ } else {
+ printf("Trying to clear already clear bit\n");
+ return -1;
+ }
+}
+
+int check_and_clear_contig_bits(u32 *word, int first, int nbits)
+{
+ for (int i = first; i < first + nbits; i++)
+ if (check_and_clear_bit(word, i) < 0)
+ return -1;
+ return 0;
+}
+
+int check_and_set_bit(u32 *word, int bit)
+{
+ /* Check that bit was clear */
+ if (!(word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit))) {
+ word[BITWISE_GETWORD(bit)] |= BITWISE_GETBIT(bit);
+ return 0;
+ } else {
+ //printf("Trying to set already set bit\n");
+ return -1;
+ }
+}
+
+
diff --git a/conts/posix/fs0/src/lib/idpool.c b/conts/posix/fs0/src/lib/idpool.c
new file mode 100644
index 0000000..0cb826e
--- /dev/null
+++ b/conts/posix/fs0/src/lib/idpool.c
@@ -0,0 +1,81 @@
+/*
+ * Used for thread and space ids.
+ *
+ * Copyright (C) 2007 Bahadir Balban
+ */
+#include
+// #include --> This requires page allocation to grow/shrink.
+#include // --> This is a local library that statically allocates its heap.
+#include
+#include INC_GLUE(memory.h)
+#include
+#include
+
+struct id_pool *id_pool_new_init(int totalbits)
+{
+ int nwords = BITWISE_GETWORD(totalbits);
+ struct id_pool *new = kzalloc((nwords * SZ_WORD)
+ + sizeof(struct id_pool));
+ if (!new)
+ return PTR_ERR(-ENOMEM);
+ new->nwords = nwords;
+ return new;
+}
+
+int id_new(struct id_pool *pool)
+{
+ int id = find_and_set_first_free_bit(pool->bitmap,
+ pool->nwords * WORD_BITS);
+ if (id < 0)
+ printf("%s: Warning! New id alloc failed\n", __FUNCTION__);
+ return id;
+}
+
+/* This finds n contiguous free ids, allocates and returns the first one */
+int ids_new_contiguous(struct id_pool *pool, int numids)
+{
+ int id = find_and_set_first_free_contig_bits(pool->bitmap,
+ pool->nwords *WORD_BITS,
+ numids);
+ if (id < 0)
+ printf("%s: Warning! New id alloc failed\n", __FUNCTION__);
+ return id;
+}
+
+/* This deletes a list of contiguous ids given the first one and number of ids */
+int ids_del_contiguous(struct id_pool *pool, int first, int numids)
+{
+ int ret;
+
+ if (pool->nwords * WORD_BITS < first + numids)
+ return -1;
+ if ((ret = check_and_clear_contig_bits(pool->bitmap, first, numids)))
+ printf("%s: Error: Invalid argument range.\n", __FUNCTION__);
+ return ret;
+}
+
+int id_del(struct id_pool *pool, int id)
+{
+ int ret;
+
+ if (pool->nwords * WORD_BITS < id)
+ return -1;
+
+ if ((ret = check_and_clear_bit(pool->bitmap, id) < 0))
+ printf("%s: Error: Could not delete id.\n", __FUNCTION__);
+ return ret;
+}
+
+/* Return a specific id, if available */
+int id_get(struct id_pool *pool, int id)
+{
+ int ret;
+
+ ret = check_and_set_bit(pool->bitmap, id);
+
+ if (ret < 0)
+ return ret;
+ else
+ return id;
+}
+
diff --git a/conts/posix/fs0/src/lib/malloc.c b/conts/posix/fs0/src/lib/malloc.c
new file mode 100644
index 0000000..27c3829
--- /dev/null
+++ b/conts/posix/fs0/src/lib/malloc.c
@@ -0,0 +1,417 @@
+/*****************************************************************************
+Simple malloc
+Chris Giese http://www.execpc.com/~geezer
+Release date: Oct 30, 2002
+This code is public domain (no copyright).
+You can do whatever you want with it.
+
+Features:
+- First-fit
+- free() coalesces adjacent free blocks
+- Uses variable-sized heap, enlarged with kbrk()/sbrk() function
+- Does not use mmap()
+- Can be easily modified to use fixed-size heap
+- Works with 16- or 32-bit compilers
+
+Build this program with either of the two main() functions, then run it.
+Messages that indicate a software error will contain three asterisks (***).
+*****************************************************************************/
+#include /* memcpy(), memset() */
+#include /* printf() */
+
+#define _32BIT 1
+
+/* use small (32K) heap for 16-bit compilers,
+large (500K) heap for 32-bit compilers */
+#if defined(_32BIT)
+#define HEAP_SIZE 500000uL
+#else
+#define HEAP_SIZE 32768u
+#endif
+
+#define MALLOC_MAGIC 0x6D92 /* must be < 0x8000 */
+
+typedef struct _malloc /* Turbo C DJGPP */
+{
+ size_t size; /* 2 bytes 4 bytes */
+ struct _malloc *next; /* 2 bytes 4 bytes */
+ unsigned magic : 15; /* 2 bytes total 4 bytes total */
+ unsigned used : 1;
+} malloc_t; /* total 6 bytes 12 bytes */
+
+static char *g_heap_bot, *g_kbrk, *g_heap_top;
+/*****************************************************************************
+*****************************************************************************/
+void dump_heap(void)
+{
+ unsigned blks_used = 0, blks_free = 0;
+ size_t bytes_used = 0, bytes_free = 0;
+ malloc_t *m;
+ int total;
+
+ printf("===============================================\n");
+ for(m = (malloc_t *)g_heap_bot; m != NULL; m = m->next)
+ {
+ printf("blk %5p: %6u bytes %s\n", m,
+ m->size, m->used ? "used" : "free");
+ if(m->used)
+ {
+ blks_used++;
+ bytes_used += m->size;
+ }
+ else
+ {
+ blks_free++;
+ bytes_free += m->size;
+ }
+ }
+ printf("blks: %6u used, %6u free, %6u total\n", blks_used,
+ blks_free, blks_used + blks_free);
+ printf("bytes: %6u used, %6u free, %6u total\n", bytes_used,
+ bytes_free, bytes_used + bytes_free);
+ printf("g_heap_bot=0x%p, g_kbrk=0x%p, g_heap_top=0x%p\n",
+ g_heap_bot, g_kbrk, g_heap_top);
+ total = (bytes_used + bytes_free) +
+ (blks_used + blks_free) * sizeof(malloc_t);
+ if(total != g_kbrk - g_heap_bot)
+ printf("*** some heap memory is not accounted for\n");
+ printf("===============================================\n");
+}
+/*****************************************************************************
+POSIX sbrk() looks like this
+ void *sbrk(int incr);
+Mine is a bit different so I can signal the calling function
+if more memory than desired was allocated (e.g. in a system with paging)
+If your kbrk()/sbrk() always allocates the amount of memory you ask for,
+this code can be easily changed.
+
+ int brk( void *sbrk( void *kbrk(
+function void *adr); int delta); int *delta);
+---------------------- ------------ ------------ -------------
+POSIX? yes yes NO
+return value if error -1 -1 NULL
+get break value . sbrk(0) int x=0; kbrk(&x);
+set break value to X brk(X) sbrk(X - sbrk(0)) int x=X, y=0; kbrk(&x) - kbrk(&y);
+enlarge heap by N bytes . sbrk(+N) int x=N; kbrk(&x);
+shrink heap by N bytes . sbrk(-N) int x=-N; kbrk(&x);
+can you tell if you're
+ given more memory
+ than you wanted? no no yes
+*****************************************************************************/
+static void *kbrk(int *delta)
+{
+ static char heap[HEAP_SIZE];
+/**/
+ char *new_brk, *old_brk;
+
+/* heap doesn't exist yet */
+ if(g_heap_bot == NULL)
+ {
+ g_heap_bot = g_kbrk = heap;
+ g_heap_top = g_heap_bot + HEAP_SIZE;
+ }
+ new_brk = g_kbrk + (*delta);
+/* too low: return NULL */
+ if(new_brk < g_heap_bot)
+ return NULL;
+/* too high: return NULL */
+ if(new_brk >= g_heap_top)
+ return NULL;
+/* success: adjust brk value... */
+ old_brk = g_kbrk;
+ g_kbrk = new_brk;
+/* ...return actual delta... (for this sbrk(), they are the same)
+ (*delta) = (*delta); */
+/* ...return old brk value */
+ return old_brk;
+}
+/*****************************************************************************
+kmalloc() and kfree() use g_heap_bot, but not g_kbrk nor g_heap_top
+*****************************************************************************/
+void *kmalloc(size_t size)
+{
+ unsigned total_size;
+ malloc_t *m, *n;
+ int delta;
+
+ if(size == 0)
+ return NULL;
+ total_size = size + sizeof(malloc_t);
+/* search heap for free block (FIRST FIT) */
+ m = (malloc_t *)g_heap_bot;
+/* g_heap_bot == 0 == NULL if heap does not yet exist */
+ if(m != NULL)
+ {
+ if(m->magic != MALLOC_MAGIC)
+// panic("kernel heap is corrupt in kmalloc()");
+ {
+ printf("*** kernel heap is corrupt in kmalloc()\n");
+ return NULL;
+ }
+ for(; m->next != NULL; m = m->next)
+ {
+ if(m->used)
+ continue;
+/* size == m->size is a perfect fit */
+ if(size == m->size)
+ m->used = 1;
+ else
+ {
+/* otherwise, we need an extra sizeof(malloc_t) bytes for the header
+of a second, free block */
+ if(total_size > m->size)
+ continue;
+/* create a new, smaller free block after this one */
+ n = (malloc_t *)((char *)m + total_size);
+ n->size = m->size - total_size;
+ n->next = m->next;
+ n->magic = MALLOC_MAGIC;
+ n->used = 0;
+/* reduce the size of this block and mark it used */
+ m->size = size;
+ m->next = n;
+ m->used = 1;
+ }
+ return (char *)m + sizeof(malloc_t);
+ }
+ }
+/* use kbrk() to enlarge (or create!) heap */
+ delta = total_size;
+ n = kbrk(&delta);
+/* uh-oh */
+ if(n == NULL)
+ return NULL;
+ if(m != NULL)
+ m->next = n;
+ n->size = size;
+ n->magic = MALLOC_MAGIC;
+ n->used = 1;
+/* did kbrk() return the exact amount of memory we wanted?
+cast to make "gcc -Wall -W ..." shut the hell up */
+ if((int)total_size == delta)
+ n->next = NULL;
+ else
+ {
+/* it returned more than we wanted (it will never return less):
+create a new, free block */
+ m = (malloc_t *)((char *)n + total_size);
+ m->size = delta - total_size - sizeof(malloc_t);
+ m->next = NULL;
+ m->magic = MALLOC_MAGIC;
+ m->used = 0;
+
+ n->next = m;
+ }
+ return (char *)n + sizeof(malloc_t);
+}
+
+static inline void *kzalloc(size_t size)
+{
+ void *buf = kmalloc(size);
+
+ memset(buf, 0, size);
+ return buf;
+}
+
+/*****************************************************************************
+*****************************************************************************/
+void kfree(void *blk)
+{
+ malloc_t *m, *n;
+
+/* get address of header */
+ m = (malloc_t *)((char *)blk - sizeof(malloc_t));
+ if(m->magic != MALLOC_MAGIC)
+// panic("attempt to kfree() block at 0x%p "
+// "with bad magic value", blk);
+ {
+ printf("*** attempt to kfree() block at 0x%p "
+ "with bad magic value\n", blk);
+ return;
+ }
+/* find this block in the heap */
+ n = (malloc_t *)g_heap_bot;
+ if(n->magic != MALLOC_MAGIC)
+// panic("kernel heap is corrupt in kfree()");
+ {
+ printf("*** kernel heap is corrupt in kfree()\n");
+ return;
+ }
+ for(; n != NULL; n = n->next)
+ {
+ if(n == m)
+ break;
+ }
+/* not found? bad pointer or no heap or something else? */
+ if(n == NULL)
+// panic("attempt to kfree() block at 0x%p "
+// "that is not in the heap", blk);
+ {
+ printf("*** attempt to kfree() block at 0x%p "
+ "that is not in the heap\n", blk);
+ return;
+ }
+/* free the block */
+ m->used = 0;
+/* coalesce adjacent free blocks
+Hard to spell, hard to do */
+ for(m = (malloc_t *)g_heap_bot; m != NULL; m = m->next)
+ {
+ while(!m->used && m->next != NULL && !m->next->used)
+ {
+/* resize this block */
+ m->size += sizeof(malloc_t) + m->next->size;
+/* merge with next block */
+ m->next = m->next->next;
+ }
+ }
+}
+/*****************************************************************************
+*****************************************************************************/
+void *krealloc(void *blk, size_t size)
+{
+ void *new_blk;
+ malloc_t *m;
+
+/* size == 0: free block */
+ if(size == 0)
+ {
+ if(blk != NULL)
+ kfree(blk);
+ new_blk = NULL;
+ }
+ else
+ {
+/* allocate new block */
+ new_blk = kmalloc(size);
+/* if allocation OK, and if old block exists, copy old block to new */
+ if(new_blk != NULL && blk != NULL)
+ {
+ m = (malloc_t *)((char *)blk - sizeof(malloc_t));
+ if(m->magic != MALLOC_MAGIC)
+// panic("attempt to krealloc() block at "
+// "0x%p with bad magic value", blk);
+ {
+ printf("*** attempt to krealloc() block at "
+ "0x%p with bad magic value\n", blk);
+ return NULL;
+ }
+/* copy minimum of old and new block sizes */
+ if(size > m->size)
+ size = m->size;
+ memcpy(new_blk, blk, size);
+/* free the old block */
+ kfree(blk);
+ }
+ }
+ return new_blk;
+}
+/*****************************************************************************
+*****************************************************************************/
+
+#if 0
+
+#include /* rand() */
+
+
+#define SLOTS 17
+
+int main(void)
+{
+ unsigned lifetime[SLOTS];
+ void *blk[SLOTS];
+ int i, j, k;
+
+ dump_heap();
+ memset(lifetime, 0, sizeof(lifetime));
+ memset(blk, 0, sizeof(blk));
+ for(i = 0; i < 1000; i++)
+ {
+ printf("Pass %6u\n", i);
+ for(j = 0; j < SLOTS; j++)
+ {
+/* age the block */
+ if(lifetime[j] != 0)
+ {
+ (lifetime[j])--;
+ continue;
+ }
+/* too old; free it */
+ if(blk[j] != NULL)
+ {
+ kfree(blk[j]);
+ blk[j] = NULL;
+ }
+/* alloc new block of random size
+Note that size_t==unsigned, but kmalloc() uses integer math,
+so block size must be positive integer */
+#if defined(_32BIT)
+ k = rand() % 40960 + 1;
+#else
+ k = rand() % 4096 + 1;
+#endif
+ blk[j] = kmalloc(k);
+ if(blk[j] == NULL)
+ printf("failed to alloc %u bytes\n", k);
+ else
+/* give it a random lifetime 0-20 */
+ lifetime[j] = rand() % 21;
+ }
+ }
+/* let's see what we've wrought */
+ printf("\n\n");
+ dump_heap();
+/* free everything */
+ for(j = 0; j < SLOTS; j++)
+ {
+ if(blk[j] != NULL)
+ {
+ kfree(blk[j]);
+ blk[j] = NULL;
+ }
+ (lifetime[j]) = 0;
+ }
+/* after all that, we should have a single, unused block */
+ dump_heap();
+ return 0;
+}
+/*****************************************************************************
+*****************************************************************************/
+
+int main(void)
+{
+ void *b1, *b2, *b3;
+
+ dump_heap();
+
+ b1 = kmalloc(42);
+ dump_heap();
+
+ b2 = kmalloc(23);
+ dump_heap();
+
+ b3 = kmalloc(7);
+ dump_heap();
+
+ b2 = krealloc(b2, 24);
+ dump_heap();
+
+ kfree(b1);
+ dump_heap();
+
+ b1 = kmalloc(5);
+ dump_heap();
+
+ kfree(b2);
+ dump_heap();
+
+ kfree(b3);
+ dump_heap();
+
+ kfree(b1);
+ dump_heap();
+
+ return 0;
+}
+#endif
+
diff --git a/conts/posix/fs0/src/lib/pathstr.c b/conts/posix/fs0/src/lib/pathstr.c
new file mode 100644
index 0000000..8492da7
--- /dev/null
+++ b/conts/posix/fs0/src/lib/pathstr.c
@@ -0,0 +1,92 @@
+/*
+ * Functions to manipulate path strings.
+ *
+ * Copyright (C) 2008 Bahadir Balban
+ */
+#include
+#include
+
+/* Reverses a string by allocating on stack. Not super-efficient but easy. */
+char *strreverse(char *str)
+{
+ int length = strlen(str);
+ char *tmp = alloca(length);
+
+ strcpy(tmp, str);
+
+ for (int i = 0; i < length; i++)
+ str[i] = tmp[length - 1 - i];
+
+ return str;
+}
+
+/*
+ * Splits the string str according to the given seperator, returns the
+ * first component, and modifies the str so that it points at the next
+ * available component (or a leading separator which can be filtered
+ * out on a subsequent call to this function).
+ */
+char *splitpath(char **str, char sep)
+{
+ char *cursor = *str;
+ char *end;
+
+ /* Move forward until no seperator */
+ while (*cursor == sep) {
+ *cursor = '\0';
+ cursor++; /* Move to first char of component */
+ }
+
+ end = cursor;
+ while (*end != sep && *end != '\0')
+ end++; /* Move until end of component */
+
+ if (*end == sep) { /* if ended with separator */
+ *end = '\0'; /* finish component by null */
+ if (*(end + 1) != '\0') /* if more components after, */
+ *str = end + 1; /* assign beginning to str */
+ else
+ *str = end; /* else str is also depleted, give null */
+ } else /* if end was null, that means the end for str, too. */
+ *str = end;
+
+ return cursor;
+}
+
+/* Same as split path, but splits components from the end. Slow. */
+char *splitpath_end(char **path, char sep)
+{
+ char *component;
+
+ /* Reverse the string */
+ strreverse(*path);
+
+ /* Pick one from the start */
+ component = splitpath(path, sep);
+
+ /* Reverse the rest back to original. */
+ strreverse(*path);
+
+ /* Reverse component back to original */
+ strreverse(component);
+
+ return component;
+}
+
+/* Splitpath test program. Tests all 3 functions.
+int main()
+{
+ char str1[256] = "/a/b/c/d/////e/f";
+ char *str2 = malloc(strlen(str1) + 1);
+ char *comp;
+
+ strcpy(str2, str1);
+
+ comp = splitpath_end(&str2, '/');
+ while (*comp) {
+ printf("%s and %s\n", comp, str2);
+ comp = splitpath_end(&str2, '/');
+ }
+}
+*/
+
diff --git a/conts/posix/fs0/src/lib/vaddr.c b/conts/posix/fs0/src/lib/vaddr.c
new file mode 100644
index 0000000..8a847a7
--- /dev/null
+++ b/conts/posix/fs0/src/lib/vaddr.c
@@ -0,0 +1,39 @@
+/*
+ * This module allocates an unused virtual address range for shm segments.
+ *
+ * Copyright (C) 2007 Bahadir Balban
+ */
+#include
+#include
+#include
+#include INC_GLUE(memory.h)
+#include
+#include
+
+void vaddr_pool_init(struct id_pool *pool, unsigned long start, unsigned long end)
+{
+ pool = id_pool_new_init(__pfn(end - start));
+}
+
+void *vaddr_new(struct id_pool *pool, int npages)
+{
+ unsigned int shm_vpfn;
+
+ if ((int)(shm_vpfn = ids_new_contiguous(pool, npages)) < 0)
+ return 0;
+
+ return (void *)__pfn_to_addr(shm_vpfn + SHM_AREA_START);
+}
+
+int vaddr_del(struct id_pool *pool, void *vaddr, int npages)
+{
+ unsigned long idpfn = __pfn(page_align(vaddr) - SHM_AREA_START);
+
+ if (ids_del_contiguous(pool, idpfn, npages) < 0) {
+ printf("%s: Invalid address range returned to "
+ "virtual address pool.\n", __FUNCTION__);
+ return -1;
+ }
+ return 0;
+}
+
diff --git a/conts/posix/fs0/src/lookup.c b/conts/posix/fs0/src/lookup.c
new file mode 100644
index 0000000..2453f6f
--- /dev/null
+++ b/conts/posix/fs0/src/lookup.c
@@ -0,0 +1,90 @@
+/*
+ * Inode lookup.
+ *
+ * Copyright (C) 2007, 2008 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * Given a dentry that has been populated by readdir with children dentries
+ * and their vnodes, this itself checks all those children on that level for
+ * a match, but it also calls lookup, which recursively checks lower levels.
+ */
+struct vnode *lookup_dentry_children(struct dentry *parentdir,
+ struct pathdata *pdata)
+{
+ struct dentry *childdir;
+ struct vnode *v;
+ const char *component = pathdata_next_component(pdata);
+
+ list_foreach_struct(childdir, &parentdir->children, child)
+ if (IS_ERR(v = childdir->vnode->ops.lookup(childdir->vnode,
+ pdata, component)))
+ /* Means not found, continue search */
+ if ((int)v == -ENOENT)
+ continue;
+ else /* A real error */
+ return v;
+ else /* No error, so found it */
+ return v;
+
+ /* Out of all children dentries, neither was a match */
+ return PTR_ERR(-ENOENT);
+}
+
+/* Lookup, recursive, assuming single-mountpoint */
+struct vnode *generic_vnode_lookup(struct vnode *thisnode,
+ struct pathdata *pdata,
+ const char *component)
+{
+ struct dentry *d;
+ struct vnode *found;
+ int err;
+
+ /* Does this path component match with any of this vnode's dentries? */
+ list_foreach_struct(d, &thisnode->dentries, vref) {
+ if (d->ops.compare(d, component)) {
+ /* Is this a directory? */
+ if (vfs_isdir(thisnode)) {
+ /* Are there more path components? */
+ if (!list_empty(&pdata->list)) {
+ /* Read directory contents */
+ if ((err = d->vnode->ops.readdir(d->vnode)) < 0)
+ return PTR_ERR(err);
+
+ /* Search all children one level below. */
+ if ((found = lookup_dentry_children(d, pdata)))
+ /* Either found, or non-zero error */
+ return found;
+ } else
+ return thisnode;
+ } else { /* Its a file */
+ if (!list_empty(&pdata->list)) /* There's still path, but not directory */
+ return PTR_ERR(-ENOTDIR);
+ else /* No path left, found it, so return file */
+ return thisnode;
+ }
+ }
+ }
+
+ /* Not found, return nothing */
+ return PTR_ERR(-ENOENT);
+}
+
+int generic_dentry_compare(struct dentry *d, const char *name)
+{
+ if (!strcmp(d->name, name) || !strcmp(name, VFS_STR_CURDIR))
+ return 1;
+ else
+ return 0;
+}
+
+struct dentry_ops generic_dentry_operations = {
+ .compare = generic_dentry_compare,
+};
+
diff --git a/conts/posix/fs0/src/memfs/file.c b/conts/posix/fs0/src/memfs/file.c
new file mode 100644
index 0000000..dd78b56
--- /dev/null
+++ b/conts/posix/fs0/src/memfs/file.c
@@ -0,0 +1,142 @@
+/*
+ * Memfs file operations
+ *
+ * Copyright (C) 2008 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include INC_GLUE(memory.h)
+
+
+#if 0
+
+/*
+ * FIXME: read_write() could be more layered using these functions.
+ */
+void *memfs_read_block(struct vnode *v, int blknum)
+{
+ void *buf = vfs_alloc_block();
+
+ if (!buf)
+ return PTR_ERR(-ENOMEM);
+
+ if(!v->block[blknum])
+ return PTR_ERR(-EEXIST);
+
+ memcpy(buf, &v->block[blknum], v->sb->blocksize);
+ return buf;
+}
+
+int memfs_write_block(struct vnode *v, int blknum, void *buf)
+{
+ if(!v->block[blknum])
+ return -EEXIST;
+
+ memcpy(&v->block[blknum], buf, v->sb->blocksize);
+ return 0;
+}
+#endif
+
+/*
+ * Handles both read and writes since most details are common.
+ *
+ * TODO: Think about whether to use inode or the vnode's fields (e.g. size)
+ * and when updated, which one is to be updated first. Normally if you use and
+ * update inode, then you sync vnode via read_vnode. but this is not really meant for
+ * this use, its meant for retrieving an unknown inode under the vnode with valid vnum.
+ * here we already have the inode.
+ */
+int memfs_file_read_write(struct vnode *v, unsigned int pfn,
+ unsigned int npages, void *buf, int wr)
+{
+ struct memfs_inode *i;
+ struct memfs_superblock *memfs_sb;
+ unsigned int start, end, count;
+ u32 blocksize;
+
+ /* Don't support different block and page sizes for now */
+ BUG_ON(v->sb->blocksize != PAGE_SIZE);
+
+ /* Buffer must be page aligned */
+ BUG_ON(!is_page_aligned(buf));
+
+ /* Low-level fs refs must be valid */
+ BUG_ON(!(i = v->inode));
+ BUG_ON(!(memfs_sb = v->sb->fs_super));
+ blocksize = v->sb->blocksize;
+
+ /* Check filesystem per-file size limit */
+ if ((pfn + npages) > memfs_sb->fmaxblocks) {
+ printf("%s: fslimit: Trying to %s outside maximum file range: %x-%x\n",
+ __FUNCTION__, (wr) ? "write" : "read", pfn, pfn + npages);
+ return -EINVAL; /* Same error that posix llseek returns */
+ }
+
+ /* Read-specific operations */
+ if (!wr) {
+ /* Find read boundaries from expected range and file's current range */
+ start = pfn < __pfn(v->size) ? pfn : __pfn(v->size);
+ end = pfn + npages < __pfn(page_align_up(v->size))
+ ? pfn + npages : __pfn(page_align_up(v->size));
+ count = end - start;
+
+ /* Copy the data from inode blocks into page buffer */
+ for (int x = start, bufpage = 0; x < end; x++, bufpage++)
+ memcpy(((void *)buf) + (bufpage * blocksize),
+ i->block[x], blocksize);
+ return (int)(count * blocksize);
+ } else { /* Write-specific operations */
+ /* Is the write beyond current file size? */
+ if (v->size < ((pfn + npages) * (blocksize))) {
+ unsigned long pagediff = pfn + npages - __pfn(v->size);
+ unsigned long holes;
+
+ /*
+ * If write is not consecutively after the currently
+ * last file block, the gap must be filled in by holes.
+ */
+ if (pfn > __pfn(v->size))
+ holes = pfn - __pfn(v->size);
+ else
+ holes = 0;
+
+ /* Allocate new blocks */
+ for (int x = 0; x < pagediff; x++)
+ if (!(i->block[__pfn(v->size) + x] =
+ memfs_alloc_block(v->sb->fs_super)))
+ return -ENOSPC;
+
+ /* Zero out the holes. FIXME: How do we zero out non-page-aligned bytes?` */
+ for (int x = 0; x < holes; x++)
+ memset(i->block[__pfn(v->size) + x], 0, blocksize);
+ }
+
+ /* Copy the data from page buffer into inode blocks */
+ for (int x = pfn, bufpage = 0; x < pfn + npages; x++, bufpage++)
+ memcpy(i->block[x], ((void *)buf) + (bufpage * blocksize), blocksize);
+ }
+
+ return (int)(npages * blocksize);
+}
+
+int memfs_file_write(struct vnode *v, unsigned long pfn, unsigned long npages, void *buf)
+{
+ return memfs_file_read_write(v, pfn, npages, buf, 1);
+}
+
+int memfs_file_read(struct vnode *v, unsigned long pfn, unsigned long npages, void *buf)
+{
+ return memfs_file_read_write(v, pfn, npages, buf, 0);
+}
+
+struct file_ops memfs_file_operations = {
+ .read = memfs_file_read,
+ .write = memfs_file_write,
+};
+
diff --git a/conts/posix/fs0/src/memfs/memfs.c b/conts/posix/fs0/src/memfs/memfs.c
new file mode 100644
index 0000000..72bb764
--- /dev/null
+++ b/conts/posix/fs0/src/memfs/memfs.c
@@ -0,0 +1,215 @@
+/*
+ * A simple read/writeable memory-only filesystem.
+ *
+ * Copyright (C) 2007, 2008 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include INC_GLUE(memory.h)
+
+struct memfs_superblock *memfs_superblock;
+
+/* Initialise allocation caches as part of superblock initialisation */
+int memfs_init_caches(struct memfs_superblock *sb)
+{
+ void *free_block;
+ struct mem_cache *block_cache;
+ struct mem_cache *inode_cache;
+
+ /* Use the whole filesystem space to initialise block cache */
+ free_block = (void *)sb + sizeof(*sb);
+ block_cache = mem_cache_init(free_block, sb->fssize - sizeof(*sb),
+ sb->blocksize, 1);
+ list_insert(&block_cache->list, &sb->block_cache_list);
+
+ /* Allocate a block and initialise it as first inode cache */
+ free_block = mem_cache_alloc(block_cache);
+ inode_cache = mem_cache_init(free_block, sb->blocksize,
+ sizeof(struct memfs_inode), 0);
+ list_insert(&inode_cache->list, &sb->inode_cache_list);
+
+ return 0;
+}
+
+/*
+ * Given an empty block buffer, initialises a filesystem there.
+ */
+int memfs_format_filesystem(void *buffer)
+{
+ struct memfs_superblock *sb = buffer; /* Buffer is the first block */
+
+ /* Zero initialise the superblock area */
+ memset(sb, 0, sizeof(*sb));
+
+ /* Initialise filesystem parameters */
+ sb->magic = MEMFS_MAGIC;
+ memcpy(sb->name, MEMFS_NAME, MEMFS_NAME_SIZE);
+ sb->blocksize = MEMFS_BLOCK_SIZE;
+ sb->fmaxblocks = MEMFS_FMAX_BLOCKS;
+ sb->fssize = MEMFS_TOTAL_SIZE;
+
+ /* Initialise block and inode index pools */
+ sb->ipool = id_pool_new_init(MEMFS_TOTAL_INODES);
+ sb->bpool = id_pool_new_init(MEMFS_TOTAL_BLOCKS);
+
+ /* Initialise bitmap allocation lists for blocks and inodes */
+ link_init(&sb->block_cache_list);
+ link_init(&sb->inode_cache_list);
+ memfs_init_caches(sb);
+
+ return 0;
+}
+
+/* Allocates a block of unused buffer */
+void *memfs_alloc_block(struct memfs_superblock *sb)
+{
+ struct mem_cache *cache;
+
+ list_foreach_struct(cache, &sb->block_cache_list, list) {
+ if (cache->free)
+ return mem_cache_zalloc(cache);
+ else
+ continue;
+ }
+ return PTR_ERR(-ENOSPC);
+}
+
+/*
+ * Even though on a list, block allocation is currently from a single cache.
+ * This frees a block back to the free buffer cache.
+ */
+int memfs_free_block(struct memfs_superblock *sb, void *block)
+{
+ struct mem_cache *c, *tmp;
+
+ list_foreach_removable_struct(c, tmp, &sb->block_cache_list, list)
+ if (!mem_cache_free(c, block))
+ return 0;
+ else
+ return -EINVAL;
+ return -EINVAL;
+}
+
+struct superblock *memfs_get_superblock(void *block);
+
+struct file_system_type memfs_fstype = {
+ .name = "memfs",
+ .magic = MEMFS_MAGIC,
+ .ops = {
+ .get_superblock = memfs_get_superblock,
+ },
+};
+
+/*
+ * Initialise root inode as a directory, as in the mknod() call
+ * but differently since root is parentless and is the parent of itself.
+ */
+int memfs_init_rootdir(struct superblock *sb)
+{
+ struct memfs_superblock *msb = sb->fs_super;
+ struct dentry *d;
+ struct vnode *v;
+
+ /*
+ * Create the root vnode. Since this is memfs, root vnode is
+ * not read-in but dynamically created here. We expect this
+ * first vnode to have vnum = 0.
+ */
+ v = sb->root = sb->ops->alloc_vnode(sb);
+ msb->root_vnum = sb->root->vnum;
+ BUG_ON(msb->root_vnum != 0);
+
+ /* Initialise fields */
+ vfs_set_type(v, S_IFDIR);
+
+ /* Allocate a new vfs dentry */
+ if (!(d = vfs_alloc_dentry()))
+ return -ENOMEM;
+
+ /*
+ * Initialise root dentry.
+ *
+ * NOTE: Root's parent is itself.
+ * Here's how it looks like in structures:
+ * root's parent is root. But root's child is not root.
+ *
+ * NOTE: Root has no name. This helps since splitpath
+ * cuts out the '/' and "" is left for root name search.
+ */
+ strncpy(d->name, VFS_STR_ROOTDIR, VFS_DNAME_MAX);
+ d->ops = generic_dentry_operations;
+ d->parent = d;
+ d->vnode = v;
+
+ /* Associate dentry with its vnode */
+ list_insert(&d->vref, &d->vnode->dentries);
+
+ /* Add both vnode and dentry to their flat caches */
+ list_insert(&d->cache_list, &dentry_cache);
+ list_insert(&v->cache_list, &vnode_cache);
+
+ return 0;
+}
+
+/* Copies fs-specific superblock into generic vfs superblock */
+struct superblock *memfs_fill_superblock(struct memfs_superblock *sb,
+ struct superblock *vfs_sb)
+{
+ vfs_sb->fs = &memfs_fstype;
+ vfs_sb->ops = &memfs_superblock_operations;
+ vfs_sb->fs_super = sb;
+ vfs_sb->fssize = sb->fssize;
+ vfs_sb->blocksize = sb->blocksize;
+
+ /* We initialise the root vnode as the root directory */
+ memfs_init_rootdir(vfs_sb);
+
+ return vfs_sb;
+}
+
+/*
+ * Probes block buffer for a valid memfs superblock, if found,
+ * allocates and copies data to a vfs superblock, and returns it.
+ */
+struct superblock *memfs_get_superblock(void *block)
+{
+ struct memfs_superblock *sb = block;
+ struct superblock *vfs_sb;
+
+ // printf("%s: %s: Reading superblock.\n", __TASKNAME__, __FUNCTION__);
+ /* We don't do sanity checks here, just confirm id. */
+ if (strcmp(sb->name, "memfs")) {
+ printf("%s: Name does not match: %s\n", __FUNCTION__, sb->name);
+ return 0;
+ }
+ if (sb->magic != MEMFS_MAGIC) {
+ printf("%s: Magic number not match: %u\n", __FUNCTION__, sb->magic);
+ return 0;
+ }
+
+ /* Allocate a vfs superblock. */
+ vfs_sb = vfs_alloc_superblock();
+
+ /* Fill generic sb from fs-specific sb */
+ return memfs_fill_superblock(sb, vfs_sb);
+}
+
+/* Registers sfs as an available filesystem type */
+void memfs_register_fstype(struct link *fslist)
+{
+ /* Initialise superblock list for this fstype */
+ link_init(&memfs_fstype.sblist);
+
+ /* Add this fstype to list of available fstypes. */
+ list_insert(&memfs_fstype.list, fslist);
+}
+
diff --git a/conts/posix/fs0/src/memfs/vnode.c b/conts/posix/fs0/src/memfs/vnode.c
new file mode 100644
index 0000000..ff1b6b0
--- /dev/null
+++ b/conts/posix/fs0/src/memfs/vnode.c
@@ -0,0 +1,427 @@
+/*
+ * Inode and vnode implementation.
+ *
+ * Copyright (C) 2008 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+struct memfs_inode *memfs_alloc_inode(struct memfs_superblock *sb)
+{
+ struct mem_cache *cache;
+ struct memfs_inode *i;
+ void *free_block;
+
+ /* Ask existing inode caches for a new inode */
+ list_foreach_struct(cache, &sb->inode_cache_list, list) {
+ if (cache->free)
+ if (!(i = mem_cache_zalloc(cache)))
+ return PTR_ERR(-ENOSPC);
+ else
+ return i;
+ else
+ continue;
+ }
+
+ /* Ask existing block caches for a new block */
+ if (IS_ERR(free_block = memfs_alloc_block(sb)))
+ return PTR_ERR(free_block);
+
+ /* Initialise it as an inode cache */
+ cache = mem_cache_init(free_block, sb->blocksize,
+ sizeof(struct memfs_inode), 0);
+ list_insert(&cache->list, &sb->inode_cache_list);
+
+ if (!(i = mem_cache_zalloc(cache)))
+ return PTR_ERR(-ENOSPC);
+ else
+ return i;
+}
+
+/*
+ * O(n^2) complexity but its simple, yet it would only reveal on high numbers.
+ */
+int memfs_free_inode(struct memfs_superblock *sb, struct memfs_inode *i)
+{
+ struct mem_cache *c, *tmp;
+
+ list_foreach_removable_struct(c, tmp, &sb->inode_cache_list, list) {
+ /* Free it, if success */
+ if (!mem_cache_free(c, i)) {
+ /* If cache completely emtpy */
+ if (mem_cache_is_empty(c)) {
+ /* Free the block, too. */
+ list_remove(&c->list);
+ memfs_free_block(sb, c);
+ }
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/* Allocates *and* initialises the inode */
+struct memfs_inode *memfs_create_inode(struct memfs_superblock *sb)
+{
+ struct memfs_inode *i;
+
+ /* Allocate the inode */
+ if (PTR_ERR(i = memfs_alloc_inode(sb)) < 0)
+ return i;
+
+ /* Allocate a new inode number */
+ if ((i->inum = id_new(sb->ipool)) < 0)
+ return i;
+
+ /* Put a reference to this inode in the inode table at this index */
+ sb->inode[i->inum] = i;
+
+ return i;
+}
+
+/* Deallocate the inode and any other closely relevant structure */
+int memfs_destroy_inode(struct memfs_superblock *sb, struct memfs_inode *i)
+{
+ int inum = i->inum;
+
+ /* Deallocate the inode */
+ if (memfs_free_inode(sb, i) < 0)
+ return -EINVAL;
+
+ /* Deallocate the inode number */
+ if (id_del(sb->ipool, inum) < 0)
+ return -EINVAL;
+
+ /* Clear the ref in inode table */
+ sb->inode[inum] = 0;
+
+ return 0;
+}
+
+/* Allocates both an inode and a vnode and associates the two together */
+struct vnode *memfs_alloc_vnode(struct superblock *sb)
+{
+ struct memfs_inode *i;
+ struct vnode *v;
+
+ /* Get a (pseudo-disk) memfs inode */
+ if (IS_ERR(i = memfs_create_inode(sb->fs_super)))
+ return PTR_ERR(i);
+
+ /* Get a vnode */
+ if (!(v = vfs_alloc_vnode()))
+ return PTR_ERR(-ENOMEM);
+
+ /* Associate the two together */
+ v->inode = i;
+ v->vnum = i->inum;
+
+ /* Associate memfs-specific fields with vnode */
+ v->ops = memfs_vnode_operations;
+ v->fops = memfs_file_operations;
+ v->sb = sb;
+
+ /* Return the vnode */
+ return v;
+}
+
+/* Frees the inode and the corresponding vnode */
+int memfs_free_vnode(struct superblock *sb, struct vnode *v)
+{
+ struct memfs_inode *i = v->inode;
+
+ BUG_ON(!i); /* Vnodes that come here must have valid inodes */
+
+ /* Destroy on-disk inode */
+ memfs_destroy_inode(sb->fs_super, i);
+
+ /* Free vnode */
+ vfs_free_vnode(v);
+
+ return 0;
+}
+
+/*
+ * Given a vnode with a valid vnum, this retrieves the corresponding
+ * inode from the filesystem.
+ */
+struct memfs_inode *memfs_read_inode(struct superblock *sb, struct vnode *v)
+{
+ struct memfs_superblock *fssb = sb->fs_super;
+
+ BUG_ON(!fssb->inode[v->vnum]);
+
+ return fssb->inode[v->vnum];
+}
+
+/*
+ * Given a preallocated vnode with a valid vnum, this reads the corresponding
+ * inode from the filesystem and fills in the vnode's fields.
+ */
+int memfs_read_vnode(struct superblock *sb, struct vnode *v)
+{
+ struct memfs_inode *i = memfs_read_inode(sb, v);
+
+ if (!i)
+ return -EEXIST;
+
+ /* Simply copy common fields */
+ v->vnum = i->inum;
+ v->size = i->size;
+ v->mode = i->mode;
+ v->owner = i->owner;
+ v->atime = i->atime;
+ v->mtime = i->mtime;
+ v->ctime = i->ctime;
+
+ return 0;
+}
+
+/* Writes a valid vnode's fields back to its fs-specific inode */
+int memfs_write_vnode(struct superblock *sb, struct vnode *v)
+{
+ struct memfs_inode *i = v->inode;
+
+ /* Vnodes that come here must have valid inodes */
+ BUG_ON(!i);
+
+ /* Simply copy common fields */
+ i->inum = v->vnum;
+ i->size = v->size;
+ i->mode = v->mode;
+ i->owner = v->owner;
+ i->atime = v->atime;
+ i->mtime = v->mtime;
+ i->ctime = v->ctime;
+
+ return 0;
+}
+
+
+/*
+ * Creates ordinary files and directories at the moment. In the future,
+ * other file types will be added. Returns the created node.
+ */
+struct vnode *memfs_vnode_mknod(struct vnode *v, const char *dirname,
+ unsigned int mode)
+{
+ struct dentry *d, *parent = link_to_struct(v->dentries.next,
+ struct dentry, vref);
+ struct memfs_dentry *memfsd;
+ struct dentry *newd;
+ struct vnode *newv;
+ int err;
+
+ /*
+ * Precautions to prove that parent is the *only* dentry,
+ * since directories can't have multiple dentries associated
+ * with them.
+ */
+ BUG_ON(list_empty(&v->dentries));
+ BUG_ON(parent->vref.next != &v->dentries);
+ BUG_ON(!vfs_isdir(v));
+
+ /* Populate the children */
+ if ((err = v->ops.readdir(v)) < 0)
+ return PTR_ERR(err);
+
+ /* Check there's no existing child with same name */
+ list_foreach_struct(d, &parent->children, child) {
+ /* Does the name exist as a child? */
+ if(d->ops.compare(d, dirname))
+ return PTR_ERR(-EEXIST);
+ }
+
+ /* Allocate a new vnode for the new directory */
+ if (IS_ERR(newv = v->sb->ops->alloc_vnode(v->sb)))
+ return newv;
+
+ /* Initialise the vnode */
+ vfs_set_type(newv, mode);
+
+ /* Get the next directory entry available on the parent vnode */
+ if (v->dirbuf.npages * PAGE_SIZE <= v->size)
+ return PTR_ERR(-ENOSPC);
+
+ /* Fill in the new entry to parent directory entry */
+ memfsd = (struct memfs_dentry *)&v->dirbuf.buffer[v->size];
+ memfsd->offset = v->size;
+ memfsd->rlength = sizeof(*memfsd);
+ memfsd->inum = ((struct memfs_inode *)newv->inode)->inum;
+ strncpy((char *)memfsd->name, dirname, MEMFS_DNAME_MAX);
+ memfsd->name[MEMFS_DNAME_MAX - 1] = '\0';
+
+ /* Write the updated directory buffer back to disk block */
+ if ((err = v->fops.write(v, 0, 1, v->dirbuf.buffer)) < 0)
+ return PTR_ERR(err); /* FIXME: free all you allocated so far */
+
+ /* Update parent vnode size */
+ v->size += sizeof(*memfsd);
+ v->sb->ops->write_vnode(v->sb, v);
+
+ /* Allocate a new vfs dentry */
+ if (!(newd = vfs_alloc_dentry()))
+ return PTR_ERR(-ENOMEM);
+
+ /* Initialise it */
+ newd->ops = generic_dentry_operations;
+ newd->parent = parent;
+ newd->vnode = newv;
+ strncpy(newd->name, dirname, VFS_DNAME_MAX);
+
+ /* Associate dentry with its vnode */
+ list_insert(&newd->vref, &newd->vnode->dentries);
+
+ /* Associate dentry with its parent */
+ list_insert(&newd->child, &parent->children);
+
+ /* Add both vnode and dentry to their flat caches */
+ list_insert(&newd->cache_list, &dentry_cache);
+ list_insert(&newv->cache_list, &vnode_cache);
+
+ return newv;
+}
+
+/*
+ * Reads the vnode directory contents into vnode's buffer in a posix-compliant
+ * struct dirent format.
+ *
+ * Reading the buffer, allocates and populates all dentries and their
+ * corresponding vnodes that are the direct children of vnode v. This means
+ * that by each call to readdir, the vfs layer increases its cache of filesystem
+ * tree by one level beneath that directory.
+ */
+int memfs_vnode_readdir(struct vnode *v)
+{
+ int err;
+ struct memfs_dentry *memfsd;
+ struct dentry *parent = link_to_struct(v->dentries.next,
+ struct dentry, vref);
+
+ /*
+ * Precautions to prove that parent is the *only* dentry,
+ * since directories can't have multiple dentries associated
+ * with them.
+ */
+ BUG_ON(parent->vref.next != &v->dentries);
+ BUG_ON(!vfs_isdir(v));
+
+ /* If a buffer is there, it means the directory is already read */
+ if (v->dirbuf.buffer)
+ return 0;
+
+ /* This is as big as a page */
+ if (IS_ERR(v->dirbuf.buffer = vfs_alloc_dirpage(v))) {
+ printf("%s: Could not allocate dirbuf.\n", __FUNCTION__);
+ return (int)v->dirbuf.buffer;
+ }
+ v->dirbuf.npages = 1;
+
+ /*
+ * Fail if vnode size is bigger than a page. Since this allocation
+ * method is to be origaced, we can live with this limitation for now.
+ */
+ BUG_ON(v->size > PAGE_SIZE);
+
+ /* Read memfsd contents into the buffer */
+ if ((err = v->fops.read(v, 0, 1, v->dirbuf.buffer)))
+ return err;
+
+ memfsd = (struct memfs_dentry *)v->dirbuf.buffer;
+
+ /* Read fs-specific directory entry into vnode and dentry caches. */
+ for (int i = 0; i < (v->size / sizeof(struct memfs_dentry)); i++) {
+ struct dentry *newd;
+ struct vnode *newv;
+
+ /* Allocate a vfs dentry */
+ if (!(newd = vfs_alloc_dentry()))
+ return -ENOMEM;
+
+ /* Initialise it */
+ newd->ops = generic_dentry_operations;
+ newd->parent = parent;
+ list_insert(&newd->child, &parent->children);
+
+ /*
+ * Lookup the vnode for dentry by its vnode number. We call
+ * vnode_lookup_byvnum instead of directly reading it because
+ * this dentry might just be a link to a vnode that's already
+ * in the vnode cache. If it's not there, the lookup function
+ * allocates and reads it for us as well.
+ */
+ newv = newd->vnode = vfs_lookup_byvnum(v->sb, memfsd[i].inum);
+ if (!newv) {
+ printf("Filesystem seems to be broken. Directory has"
+ "inode number: %d, but no such inode found.\n",
+ memfsd[i].inum);
+ BUG();
+ }
+
+ /* Assing this dentry as a name of its vnode */
+ list_insert(&newd->vref, &newd->vnode->dentries);
+
+ /* Increase link count */
+ newv->links++;
+
+ /* Copy fields into generic dentry */
+ memcpy(newd->name, memfsd[i].name, MEMFS_DNAME_MAX);
+
+ /* Add both vnode and dentry to their caches */
+ list_insert(&newd->cache_list, &dentry_cache);
+ list_insert(&newv->cache_list, &vnode_cache);
+ }
+
+ return 0;
+}
+
+/*
+ * Copies fs-specific dirent data into user buffer in
+ * generic struct dirent format.
+ */
+int memfs_vnode_filldir(void *userbuf, struct vnode *v, int count)
+{
+ int nbytes;
+ int err;
+
+ /* Bytes to read, minimum of vnode size and count requested */
+ nbytes = (v->size <= count) ? v->size : count;
+
+ /* Read the dir content from fs, if haven't done so yet */
+ if ((err = v->ops.readdir(v)) < 0)
+ return err;
+
+ /* Do we have those bytes at hand? */
+ if (v->dirbuf.buffer && (v->dirbuf.npages * PAGE_SIZE) >= nbytes) {
+ /*
+ * Memfs does a direct copy since memfs dirent format
+ * is the same as generic dirent format.
+ */
+ memcpy(userbuf, v->dirbuf.buffer, nbytes);
+ return nbytes;
+ }
+ return 0;
+}
+
+struct vnode_ops memfs_vnode_operations = {
+ .readdir = memfs_vnode_readdir,
+ .filldir = memfs_vnode_filldir,
+ .mknod = memfs_vnode_mknod,
+ .lookup = generic_vnode_lookup,
+};
+
+struct superblock_ops memfs_superblock_operations = {
+ .read_vnode = memfs_read_vnode,
+ .write_vnode = memfs_write_vnode,
+ .alloc_vnode = memfs_alloc_vnode,
+ .free_vnode = memfs_free_vnode,
+};
+
diff --git a/conts/posix/fs0/src/path.c b/conts/posix/fs0/src/path.c
new file mode 100644
index 0000000..e5719b6
--- /dev/null
+++ b/conts/posix/fs0/src/path.c
@@ -0,0 +1,145 @@
+/*
+ * Path manipulation functions.
+ *
+ * Copyright (C) 2008 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+const char *pathdata_next_component(struct pathdata *pdata)
+{
+ struct pathcomp *p, *n;
+ const char *pathstr;
+
+ list_foreach_removable_struct(p, n, &pdata->list, list) {
+ list_remove(&p->list);
+ pathstr = p->str;
+ kfree(p);
+ return pathstr;
+ }
+ return "";
+}
+
+/* Check there's at least one element, unlink and return the last element */
+const char *pathdata_last_component(struct pathdata *pdata)
+{
+ struct pathcomp *p;
+ const char *pathstr;
+
+ if (!list_empty(&pdata->list)) {
+ p = link_to_struct(pdata->list.prev, struct pathcomp, list);
+ list_remove(&p->list);
+ pathstr = p->str;
+ kfree(p);
+ return pathstr;
+ }
+
+ return "";
+}
+
+/* Unlink and free all path components in pathdata, and then free pathdata */
+void pathdata_destroy(struct pathdata *p)
+{
+ struct pathcomp *c, *n;
+
+ list_foreach_removable_struct(c, n, &p->list, list) {
+ list_remove(&c->list);
+ kfree(c);
+ }
+ kfree(p);
+}
+
+void pathdata_print(struct pathdata *p)
+{
+ struct pathcomp *comp;
+
+ printf("Extracted path is:\n");
+ list_foreach_struct(comp, &p->list, list)
+ printf("%s\n", comp->str);
+}
+
+/* Extracts all path components from pathname into more presentable form */
+struct pathdata *pathdata_parse(const char *pathname,
+ char *pathbuf, struct tcb *task)
+{
+ struct pathdata *pdata = kzalloc(sizeof(*pdata));
+ struct pathcomp *comp;
+ char *str;
+
+ if (!pdata)
+ return PTR_ERR(-ENOMEM);
+
+ /* Initialise pathdata */
+ link_init(&pdata->list);
+ strcpy(pathbuf, pathname);
+
+ /* First component is root if there's a root */
+ if (pathname[0] == VFS_CHAR_SEP) {
+ if (!(comp = kzalloc(sizeof(*comp)))) {
+ kfree(pdata);
+ return PTR_ERR(-ENOMEM);
+ }
+ link_init(&comp->list);
+ comp->str = VFS_STR_ROOTDIR;
+ list_insert_tail(&comp->list, &pdata->list);
+
+ if (task)
+ /* Lookup start vnode is root vnode */
+ pdata->vstart = task->fs_data->rootdir;
+ else /* If no task, we use the root mountpoint pivot vnode */
+ pdata->vstart = vfs_root.pivot;
+
+ /* Otherwise start from current directory */
+ } else {
+ struct dentry *curdir;
+
+ if (!(comp = kzalloc(sizeof(*comp)))) {
+ kfree(pdata);
+ return PTR_ERR(-ENOMEM);
+ }
+ link_init(&comp->list);
+
+ /* Get current dentry for this task */
+ curdir = link_to_struct(task->fs_data->curdir->dentries.next,
+ struct dentry, vref);
+
+ /* Use its name in path component */
+ comp->str = curdir->name;
+ list_insert_tail(&comp->list, &pdata->list);
+
+ /* Lookup start vnode is current dir vnode */
+ pdata->vstart = task->fs_data->curdir;
+ }
+
+ /* Add every other path component */
+ str = splitpath(&pathbuf, VFS_CHAR_SEP);
+ while(*str) {
+ /* Any curdir components in path are ignored. */
+ if (!strcmp(str, VFS_STR_CURDIR)) {
+ ;
+ } else {
+ if (!(comp = kzalloc(sizeof(*comp)))) {
+ pathdata_destroy(pdata);
+ return PTR_ERR(-ENOMEM);
+ }
+ link_init(&comp->list);
+ comp->str = str;
+ list_insert_tail(&comp->list, &pdata->list);
+ }
+
+ /* Next component */
+ str = splitpath(&pathbuf, VFS_CHAR_SEP);
+ }
+ // pathdata_print(pdata);
+
+ return pdata;
+}
+
diff --git a/conts/posix/fs0/src/romfs/romfs.c b/conts/posix/fs0/src/romfs/romfs.c
new file mode 100644
index 0000000..d225ec5
--- /dev/null
+++ b/conts/posix/fs0/src/romfs/romfs.c
@@ -0,0 +1,86 @@
+#include
+#include
+#include
+#include
+#include
+#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");
+ }
+
+}
+
+
diff --git a/conts/posix/fs0/src/romfs/romfs.h b/conts/posix/fs0/src/romfs/romfs.h
new file mode 100644
index 0000000..fed9ab7
--- /dev/null
+++ b/conts/posix/fs0/src/romfs/romfs.h
@@ -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__ */
diff --git a/conts/posix/fs0/src/romfs/romfs_fs.h b/conts/posix/fs0/src/romfs/romfs_fs.h
new file mode 100644
index 0000000..e20bbf9
--- /dev/null
+++ b/conts/posix/fs0/src/romfs/romfs_fs.h
@@ -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
diff --git a/conts/posix/fs0/src/syscalls.c b/conts/posix/fs0/src/syscalls.c
new file mode 100644
index 0000000..9943c44
--- /dev/null
+++ b/conts/posix/fs0/src/syscalls.c
@@ -0,0 +1,528 @@
+/*
+ * Some syscall stubs
+ *
+ * Copyright (C) 2008 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define NILFD -1
+
+/*
+ * This informs mm0 about an opened file descriptors.
+ *
+ * MM0 *also* keeps track of fd's because mm0 is a better candidate
+ * for handling syscalls that access file content (i.e. read/write) since
+ * it maintains the page cache. MM0 is not notified about opened files
+ * but is rather informed when it asks to be. This avoids deadlocks by
+ * keeping the request flow in one way.
+ */
+
+int pager_sys_open(struct tcb *pager, l4id_t opener, int fd)
+{
+ struct tcb *task;
+ struct vnode *v;
+
+ //printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
+ if (pager->tid != PAGER_TID)
+ return -EINVAL;
+
+ /* Check if such task exists */
+ if (!(task = find_task(opener)))
+ return -ESRCH;
+
+ /* Check if that fd has been opened */
+ if (task->files->fd[fd] == NILFD)
+ return -EBADF;
+
+ /* Search the vnode by that vnum */
+ if (IS_ERR(v = vfs_lookup_byvnum(vfs_root.pivot->sb,
+ task->files->fd[fd])))
+ return (int)v;
+
+ /*
+ * Write file information, they will
+ * be sent via the return origy.
+ */
+ write_mr(L4SYS_ARG0, v->vnum);
+ write_mr(L4SYS_ARG1, v->size);
+
+ return 0;
+}
+
+/* This is called when the pager needs to open a vfs file via its path */
+int pager_open_bypath(struct tcb *pager, char *pathname)
+{
+ struct pathdata *pdata;
+ struct tcb *task;
+ struct vnode *v;
+ int retval;
+
+ //printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
+ if (pager->tid != PAGER_TID)
+ return -EINVAL;
+
+ /* Parse path data */
+ if (IS_ERR(pdata = pathdata_parse(pathname,
+ alloca(strlen(pathname) + 1),
+ task)))
+ return (int)pdata;
+
+ /* Search the vnode by that path */
+ if (IS_ERR(v = vfs_lookup_bypath(pdata))) {
+ retval = (int)v;
+ goto out;
+ }
+
+ /*
+ * Write file information, they will
+ * be sent via the return origy.
+ */
+ write_mr(L4SYS_ARG0, v->vnum);
+ write_mr(L4SYS_ARG1, v->size);
+
+ return 0;
+
+out:
+ pathdata_destroy(pdata);
+ return retval;
+
+}
+
+
+/* Directories only for now */
+void print_vnode(struct vnode *v)
+{
+ struct dentry *d, *c;
+
+ printf("Vnode names:\n");
+ list_foreach_struct(d, &v->dentries, vref) {
+ printf("%s\n", d->name);
+ printf("Children dentries:\n");
+ list_foreach_struct(c, &d->children, child)
+ printf("%s\n", c->name);
+ }
+}
+
+/* Creates a node under a directory, e.g. a file, directory. */
+struct vnode *vfs_create(struct tcb *task, struct pathdata *pdata,
+ unsigned int mode)
+{
+ struct vnode *vparent, *newnode;
+ const char *nodename;
+
+ /* The last component is to be created */
+ nodename = pathdata_last_component(pdata);
+
+ /* Check that the parent directory exists. */
+ if (IS_ERR(vparent = vfs_lookup_bypath(pdata)))
+ return vparent;
+
+ /* The parent vnode must be a directory. */
+ if (!vfs_isdir(vparent))
+ return PTR_ERR(-ENOENT);
+
+ /* Create new directory under the parent */
+ if (IS_ERR(newnode = vparent->ops.mknod(vparent, nodename, mode)))
+ return newnode;
+
+ // print_vnode(vparent);
+ return newnode;
+}
+
+/*
+ * Pager notifies vfs about a closed file descriptor.
+ *
+ * FIXME: fsync + close could be done under a single "close" ipc
+ * from pager. Currently there are 2 ipcs: 1 fsync + 1 fd close.
+ */
+int pager_sys_close(struct tcb *sender, l4id_t closer, int fd)
+{
+ struct tcb *task;
+ int err;
+
+ // printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
+
+ BUG_ON(!(task = find_task(closer)));
+
+ if ((err = id_del(task->files->fdpool, fd)) < 0) {
+ printf("%s: Error releasing fd identifier.\n",
+ __FUNCTION__);
+ return err;
+ }
+ task->files->fd[fd] = NILFD;
+
+ return 0;
+}
+
+/* FIXME:
+ * - Is it already open?
+ * - Allocate a copy of path string since lookup destroys it
+ * - Check flags and mode.
+ */
+int sys_open(struct tcb *task, const char *pathname, int flags, unsigned int mode)
+{
+ struct pathdata *pdata;
+ struct vnode *v;
+ int fd;
+ int retval;
+
+ // printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
+
+ /* Parse path data */
+ if (IS_ERR(pdata = pathdata_parse(pathname,
+ alloca(strlen(pathname) + 1),
+ task)))
+ return (int)pdata;
+
+ /* Creating new file */
+ if (flags & O_CREAT) {
+ /* Make sure mode identifies a file */
+ mode |= S_IFREG;
+ if (IS_ERR(v = vfs_create(task, pdata, mode))) {
+ retval = (int)v;
+ goto out;
+ }
+ } else {
+ /* Not creating, just opening, get the vnode */
+ if (IS_ERR(v = vfs_lookup_bypath(pdata))) {
+ retval = (int)v;
+ goto out;
+ }
+ }
+
+ /* Get a new fd */
+ BUG_ON((fd = id_new(task->files->fdpool)) < 0);
+ retval = fd;
+
+ /* Assign the new fd with the vnode's number */
+ task->files->fd[fd] = v->vnum;
+
+out:
+ pathdata_destroy(pdata);
+ return retval;
+}
+
+int sys_mkdir(struct tcb *task, const char *pathname, unsigned int mode)
+{
+ struct pathdata *pdata;
+ struct vnode *v;
+ int ret = 0;
+
+ /* Parse path data */
+ if (IS_ERR(pdata = pathdata_parse(pathname,
+ alloca(strlen(pathname) + 1),
+ task)))
+ return (int)pdata;
+
+ /* Make sure we create a directory */
+ mode |= S_IFDIR;
+
+ /* Create the directory or fail */
+ if (IS_ERR(v = vfs_create(task, pdata, mode)))
+ ret = (int)v;
+
+ /* Destroy extracted path data */
+ pathdata_destroy(pdata);
+ return ret;
+}
+
+int sys_chdir(struct tcb *task, const char *pathname)
+{
+ struct vnode *v;
+ struct pathdata *pdata;
+ int ret = 0;
+
+ /* Parse path data */
+ if (IS_ERR(pdata = pathdata_parse(pathname,
+ alloca(strlen(pathname) + 1),
+ task)))
+ return (int)pdata;
+
+ /* Get the vnode */
+ if (IS_ERR(v = vfs_lookup_bypath(pdata))) {
+ ret = (int)v;
+ goto out;
+ }
+
+ /* Ensure it's a directory */
+ if (!vfs_isdir(v)) {
+ ret = -ENOTDIR;
+ goto out;
+ }
+
+ /* Assign the current directory pointer */
+ task->fs_data->curdir = v;
+
+out:
+ /* Destroy extracted path data */
+ pathdata_destroy(pdata);
+ return ret;
+}
+
+void fill_kstat(struct vnode *v, struct kstat *ks)
+{
+ ks->vnum = (u64)v->vnum;
+ ks->mode = v->mode;
+ ks->links = v->links;
+ ks->uid = v->owner & 0xFFFF;
+ ks->gid = (v->owner >> 16) & 0xFFFF;
+ ks->size = v->size;
+ ks->blksize = v->sb->blocksize;
+ ks->atime = v->atime;
+ ks->mtime = v->mtime;
+ ks->ctime = v->ctime;
+}
+
+int sys_fstat(struct tcb *task, int fd, void *statbuf)
+{
+ struct vnode *v;
+ unsigned long vnum;
+
+ /* Get the vnum */
+ if (fd < 0 || fd > TASK_FILES_MAX || task->files->fd[fd] == NILFD)
+ return -EBADF;
+
+ vnum = task->files->fd[fd];
+
+ /* Lookup vnode */
+ if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
+ return -EINVAL;
+
+ /* Fill in the c0-style stat structure */
+ fill_kstat(v, statbuf);
+
+ return 0;
+}
+
+/*
+ * Returns codezero-style stat structure which in turn is
+ * converted to posix style stat structure via the libposix
+ * library in userspace.
+ */
+int sys_stat(struct tcb *task, const char *pathname, void *statbuf)
+{
+ struct vnode *v;
+ struct pathdata *pdata;
+ int ret = 0;
+
+ /* Parse path data */
+ if (IS_ERR(pdata = pathdata_parse(pathname,
+ alloca(strlen(pathname) + 1),
+ task)))
+ return (int)pdata;
+
+ /* Get the vnode */
+ if (IS_ERR(v = vfs_lookup_bypath(pdata))) {
+ ret = (int)v;
+ goto out;
+ }
+
+ /* Fill in the c0-style stat structure */
+ fill_kstat(v, statbuf);
+
+out:
+ /* Destroy extracted path data */
+ pathdata_destroy(pdata);
+ return ret;
+}
+
+/*
+ * Note this can be solely called by the pager and is not the posix read call.
+ * That call is in the pager. This merely supplies the pages the pager needs
+ * if they're not in the page cache.
+ */
+int pager_sys_read(struct tcb *pager, unsigned long vnum, unsigned long f_offset,
+ unsigned long npages, void *pagebuf)
+{
+ struct vnode *v;
+
+ // printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
+
+ if (pager->tid != PAGER_TID)
+ return -EINVAL;
+
+ /* Lookup vnode */
+ if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
+ return -EINVAL;
+
+ /* Ensure vnode is not a directory */
+ if (vfs_isdir(v))
+ return -EISDIR;
+
+ return v->fops.read(v, f_offset, npages, pagebuf);
+}
+
+int pager_update_stats(struct tcb *pager, unsigned long vnum,
+ unsigned long newsize)
+{
+ struct vnode *v;
+
+ // printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
+
+ if (pager->tid != PAGER_TID)
+ return -EINVAL;
+
+ /* Lookup vnode */
+ if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
+ return -EINVAL;
+
+ v->size = newsize;
+ v->sb->ops->write_vnode(v->sb, v);
+
+ return 0;
+}
+
+/*
+ * This can be solely called by the pager and is not the posix write call.
+ * That call is in the pager. This writes the dirty pages of a file
+ * back to disk via vfs.
+ *
+ * The buffer must be contiguous by page, if npages > 1.
+ */
+int pager_sys_write(struct tcb *pager, unsigned long vnum, unsigned long f_offset,
+ unsigned long npages, void *pagebuf)
+{
+ struct vnode *v;
+ int ret;
+ int fwrite_end;
+
+ // printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
+
+ if (pager->tid != PAGER_TID)
+ return -EINVAL;
+
+ /* Lookup vnode */
+ if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
+ return -EINVAL;
+
+ /* Ensure vnode is not a directory */
+ if (vfs_isdir(v))
+ return -EISDIR;
+
+ //printf("%s/%s: Writing to vnode %lu, at pgoff 0x%x, %d pages, buf at 0x%x\n",
+ // __TASKNAME__, __FUNCTION__, vnum, f_offset, npages, pagebuf);
+
+ if ((ret = v->fops.write(v, f_offset, npages, pagebuf)) < 0)
+ return ret;
+
+ /*
+ * If the file is extended, write silently extends it.
+ * We update the extended size here. Otherwise subsequent write's
+ * may fail by relying on wrong file size.
+ */
+ fwrite_end = __pfn_to_addr(f_offset) + ret;
+ if (v->size < fwrite_end) {
+ v->size = fwrite_end;
+ v->sb->ops->write_vnode(v->sb, v);
+ }
+
+ return ret;
+}
+
+/*
+ * FIXME: Here's how this should have been:
+ * v->ops.readdir() -> Reads fs-specific directory contents. i.e. reads
+ * the directory buffer, doesn't care however contained vnode details are
+ * stored.
+ *
+ * After reading, it converts the fs-spceific contents into generic vfs
+ * dentries and populates the dentries of those vnodes.
+ *
+ * If vfs_readdir() is issued, those generic dentries are converted into
+ * the posix-defined directory record structure. During this on-the-fly
+ * generation, pseudo-entries such as . and .. are also added.
+ *
+ * If this layering is not done, i.e. the low-level dentry buffer already
+ * keeps this record structure and we try to return that, then we wont
+ * have a chance to add the pseudo-entries . and .. These record entries
+ * are essentially created from parent vnode and current vnode but using
+ * the names . and ..
+ */
+
+int fill_dirent(void *buf, unsigned long vnum, int offset, char *name)
+{
+ struct dirent *d = buf;
+
+ d->inum = (unsigned int)vnum;
+ d->offset = offset;
+ d->rlength = sizeof(struct dirent);
+ strncpy((char *)d->name, name, DIRENT_NAME_MAX);
+
+ return d->rlength;
+}
+
+/*
+ * Reads @count bytes of posix struct dirents into @buf. This implements
+ * the raw dirent read syscall upon which readdir() etc. posix calls
+ * can be built in userspace.
+ *
+ * FIXME: Ensure buf is in shared utcb, and count does not exceed it.
+ */
+int sys_readdir(struct tcb *t, int fd, void *buf, int count)
+{
+ int dirent_size = sizeof(struct dirent);
+ int total = 0, nbytes = 0;
+ unsigned long vnum;
+ struct vnode *v;
+ struct dentry *d;
+
+ // printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
+
+ /* Check address is in task's utcb */
+ if ((unsigned long)buf < t->shpage_address ||
+ (unsigned long)buf > t->shpage_address + PAGE_SIZE)
+ return -EINVAL;
+
+ if (fd < 0 || fd > TASK_FILES_MAX || t->files->fd[fd] == NILFD)
+ return -EBADF;
+
+ vnum = t->files->fd[fd];
+
+ /* Lookup vnode */
+ if (!(v = vfs_lookup_byvnum(vfs_root.pivot->sb, vnum)))
+ return -EINVAL;
+
+ d = link_to_struct(v->dentries.next, struct dentry, vref);
+
+ /* Ensure vnode is a directory */
+ if (!vfs_isdir(v))
+ return -ENOTDIR;
+
+ /* Write pseudo-entries . and .. to user buffer */
+ if (count < dirent_size)
+ return 0;
+
+ fill_dirent(buf, v->vnum, nbytes, VFS_STR_CURDIR);
+ nbytes += dirent_size;
+ buf += dirent_size;
+ count -= dirent_size;
+
+ if (count < dirent_size)
+ return 0;
+
+ fill_dirent(buf, d->parent->vnode->vnum, nbytes, VFS_STR_PARDIR);
+ nbytes += dirent_size;
+ buf += dirent_size;
+ count -= dirent_size;
+
+ /* Copy fs-specific dir to buf in struct dirent format */
+ if ((total = v->ops.filldir(buf, v, count)) < 0)
+ return total;
+
+ return nbytes + total;
+}
+
diff --git a/conts/posix/fs0/src/task.c b/conts/posix/fs0/src/task.c
new file mode 100644
index 0000000..c0b7bb2
--- /dev/null
+++ b/conts/posix/fs0/src/task.c
@@ -0,0 +1,315 @@
+/*
+ * FS0 task data initialisation.
+ *
+ * Copyright (C) 2008 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+extern void *shared_page;
+
+struct global_list global_tasks = {
+ .list = { &global_tasks.list, &global_tasks.list },
+ .total = 0,
+};
+
+void global_add_task(struct tcb *task)
+{
+ BUG_ON(!list_empty(&task->list));
+ list_insert_tail(&task->list, &global_tasks.list);
+ global_tasks.total++;
+}
+
+void global_remove_task(struct tcb *task)
+{
+ BUG_ON(list_empty(&task->list));
+ list_remove_init(&task->list);
+ BUG_ON(--global_tasks.total < 0);
+}
+
+struct tcb *find_task(int tid)
+{
+ struct tcb *t;
+
+ list_foreach_struct(t, &global_tasks.list, list)
+ if (t->tid == tid)
+ return t;
+ return 0;
+}
+
+/* Allocate a vfs task structure according to given flags */
+struct tcb *tcb_alloc_init(unsigned int flags)
+{
+ struct tcb *task;
+
+ if (!(task = kzalloc(sizeof(struct tcb))))
+ return PTR_ERR(-ENOMEM);
+
+ /* Allocate new fs data struct if its not shared */
+ if (!(flags & TCB_SHARED_FS)) {
+ if (!(task->fs_data =
+ kzalloc(sizeof(*task->fs_data)))) {
+ kfree(task);
+ return PTR_ERR(-ENOMEM);
+ }
+ task->fs_data->tcb_refs = 1;
+ }
+
+ /* Allocate file structures if not shared */
+ if (!(flags & TCB_SHARED_FILES)) {
+ if (!(task->files =
+ kzalloc(sizeof(*task->files)))) {
+ kfree(task->fs_data);
+ kfree(task);
+ return PTR_ERR(-ENOMEM);
+ }
+ if (IS_ERR(task->files->fdpool =
+ id_pool_new_init(TASK_FILES_MAX))) {
+ void *err = task->files->fdpool;
+
+ kfree(task->files);
+ kfree(task->fs_data);
+ kfree(task);
+ return err;
+ }
+ task->files->tcb_refs = 1;
+ }
+
+ /* Ids will be set up later */
+ task->tid = TASK_ID_INVALID;
+
+ /* Initialise list structure */
+ link_init(&task->list);
+
+ return task;
+}
+
+void copy_tcb(struct tcb *to, struct tcb *from, unsigned int share_flags)
+{
+ if (share_flags & TCB_SHARED_FILES) {
+ to->files = from->files;
+ to->files->tcb_refs++;
+ } else {
+ /* Copy all file descriptors */
+ memcpy(to->files->fd, from->files->fd,
+ TASK_FILES_MAX * sizeof(to->files->fd[0]));
+
+ /* Copy the idpool */
+ id_pool_copy(to->files->fdpool, from->files->fdpool, TASK_FILES_MAX);
+ }
+
+ if (share_flags & TCB_SHARED_FS) {
+ to->fs_data = from->fs_data;
+ to->fs_data->tcb_refs++;
+ } else
+ memcpy(to->fs_data, from->fs_data, sizeof(*to->fs_data));
+}
+
+/* Allocate a task struct and initialise it */
+struct tcb *tcb_create(struct tcb *orig, l4id_t tid, unsigned long shpage,
+ unsigned int share_flags)
+{
+ struct tcb *task;
+
+ /* Can't have some share flags with no original task */
+ BUG_ON(!orig && share_flags);
+
+ /* Create a task and use given space and thread ids. */
+ if (IS_ERR(task = tcb_alloc_init(share_flags)))
+ return task;
+
+ task->tid = tid;
+ task->shpage_address = shpage;
+
+ /*
+ * If there's an original task that means this will be a full
+ * or partial copy of it. We copy depending on share_flags.
+ */
+ if (orig)
+ copy_tcb(task, orig, share_flags);
+
+ return task;
+}
+
+/* Free shared structures if no references left */
+void tcb_free_resources(struct tcb *task)
+{
+
+ if (--task->fs_data->tcb_refs == 0)
+ kfree(task->fs_data);
+
+ if (--task->files->tcb_refs == 0) {
+ kfree(task->files->fdpool);
+ kfree(task->files);
+ }
+
+}
+
+void tcb_destroy(struct tcb *task)
+{
+ global_remove_task(task);
+
+ tcb_free_resources(task);
+
+ kfree(task);
+}
+
+/*
+ * Attaches to task's utcb. TODO: Add SHM_RDONLY and test it.
+ * FIXME: This calls the pager and is a potential for deadlock
+ * it only doesn't lock because it is called during initialisation.
+ */
+int task_utcb_attach(struct tcb *t)
+{
+ int shmid;
+ void *shmaddr;
+
+ /* Use it as a key to create a shared memory region */
+ if ((shmid = shmget((key_t)t->shpage_address, PAGE_SIZE, 0)) == -1)
+ goto out_err;
+
+ /* Attach to the region */
+ if ((int)(shmaddr = shmat(shmid, (void *)t->shpage_address, 0)) == -1)
+ goto out_err;
+
+ /* Ensure address is right */
+ if ((unsigned long)shmaddr != t->shpage_address)
+ return -EINVAL;
+
+ // printf("%s: Mapped shared page of task %d @ 0x%x\n",
+ // __TASKNAME__, t->tid, shmaddr);
+
+ return 0;
+
+out_err:
+ printf("%s: Mapping utcb of task %d failed with err: %d.\n",
+ __TASKNAME__, t->tid, errno);
+ return -EINVAL;
+}
+
+/*
+ * Receives ipc from pager about a new fork event and
+ * the information on the resulting child task.
+ */
+int pager_notify_fork(struct tcb *sender, l4id_t parentid,
+ l4id_t childid, unsigned long shpage_address,
+ unsigned int flags)
+{
+ struct tcb *child, *parent;
+
+ // printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
+ BUG_ON(!(parent = find_task(parentid)));
+
+ /* Create a child vfs tcb using given parent and copy flags */
+ if (IS_ERR(child = tcb_create(parent, childid, shpage_address, flags)))
+ return (int)child;
+
+ global_add_task(child);
+
+ // printf("%s/%s: Exiting...\n", __TASKNAME__, __FUNCTION__);
+ return 0;
+}
+
+
+/*
+ * Pager tells us that a task is exiting by this call.
+ */
+int pager_notify_exit(struct tcb *sender, l4id_t tid)
+{
+ struct tcb *task;
+
+ // printf("%s/%s\n", __TASKNAME__, __FUNCTION__);
+ BUG_ON(!(task = find_task(tid)));
+
+ tcb_destroy(task);
+
+ // printf("%s/%s: Exiting...\n", __TASKNAME__, __FUNCTION__);
+
+ return 0;
+}
+
+
+/* Read task information into the utcb page, since it won't fit into mrs. */
+struct task_data_head *receive_pager_taskdata(void)
+{
+ int err;
+
+ /* Make the actual ipc call */
+ if ((err = l4_sendrecv(PAGER_TID, PAGER_TID,
+ L4_IPC_TAG_TASKDATA)) < 0) {
+ printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
+ return PTR_ERR(err);
+ }
+
+ /* Check if call itself was successful */
+ if ((err = l4_get_retval()) < 0) {
+ printf("%s: Error: %d.\n", __FUNCTION__, err);
+ return PTR_ERR(err);
+ }
+
+ /* Data is expected in the utcb page */
+ // printf("%s: %d Total tasks.\n", __FUNCTION__,
+ // ((struct task_data_head *)shared_page)->total);
+
+ return (struct task_data_head *)shared_page;
+}
+
+
+int init_task_structs(struct task_data_head *tdata_head)
+{
+ struct tcb *t;
+
+ for (int i = 0; i < tdata_head->total; i++) {
+ /* New tcb with fields sent by pager */
+ if (IS_ERR(t = tcb_create(0, tdata_head->tdata[i].tid,
+ tdata_head->tdata[i].shpage_address,
+ 0)))
+ return (int)t;
+
+ /* Initialise vfs specific fields. */
+ t->fs_data->rootdir = vfs_root.pivot;
+ t->fs_data->curdir = vfs_root.pivot;
+
+ /* Print task information */
+ //printf("%s: Task info received from mm0:\n", __TASKNAME__);
+ //printf("%s: task id: %d, utcb address: 0x%x\n",
+ // __TASKNAME__, t->tid, t->utcb_address);
+
+ /* shm attach to the utcbs for all these tasks except own */
+ if (t->tid != self_tid())
+ task_utcb_attach(t);
+ global_add_task(t);
+ }
+
+ return 0;
+}
+
+int init_task_data(void)
+{
+ struct task_data_head *tdata_head;
+
+ /* Read how many tasks and tids of each */
+ BUG_ON((tdata_head = receive_pager_taskdata()) < 0);
+
+ /* Initialise local task structs using this info */
+ BUG_ON(init_task_structs(tdata_head) < 0);
+
+ return 0;
+}
+
diff --git a/conts/posix/fs0/src/vfs.c b/conts/posix/fs0/src/vfs.c
new file mode 100644
index 0000000..3752fa3
--- /dev/null
+++ b/conts/posix/fs0/src/vfs.c
@@ -0,0 +1,84 @@
+/*
+ * High-level vfs implementation.
+ *
+ * Copyright (C) 2008 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+
+LINK_DECLARE(vnode_cache);
+LINK_DECLARE(dentry_cache);
+
+/*
+ * /
+ * /boot
+ * /boot/images/mm0.axf
+ * /boot/images/fs0.axf
+ * /boot/images/test0.axf
+ * /file.txt
+ */
+struct vfs_mountpoint vfs_root;
+
+/*
+ * Vnodes in the vnode cache have 2 keys. One is their dentry names, the other
+ * is their vnum. This one checks the vnode cache by the given vnum first.
+ * If nothing is found, it reads the vnode from disk into cache. This is called
+ * by system calls since tasks keep an fd-to-vnum table.
+ */
+struct vnode *vfs_lookup_byvnum(struct superblock *sb, unsigned long vnum)
+{
+ struct vnode *v;
+ int err;
+
+ /* Check the vnode flat list by vnum */
+ list_foreach_struct(v, &vnode_cache, cache_list)
+ if (v->vnum == vnum)
+ return v;
+
+ /* Check the actual filesystem for the vnode */
+ v = vfs_alloc_vnode();
+ v->vnum = vnum;
+
+ /* Note this only checks given superblock */
+ if ((err = sb->ops->read_vnode(sb, v)) < 0) {
+ vfs_free_vnode(v);
+ return PTR_ERR(err);
+ }
+
+ /* Add the vnode back to vnode flat list */
+ list_insert(&v->cache_list, &vnode_cache);
+
+ return v;
+}
+
+/*
+ * Vnodes in the vnode cache have 2 keys. One is the set of dentry names they
+ * have, the other is their vnum. This one checks the vnode cache by the path
+ * first. If nothing is found, it reads the vnode from disk into the cache.
+ */
+struct vnode *vfs_lookup_bypath(struct pathdata *pdata)
+{
+ const char *firstcomp;
+
+ /*
+ * This does vfs cache + fs lookup.
+ */
+ BUG_ON(list_empty(&pdata->list));
+ firstcomp = pathdata_next_component(pdata);
+ return pdata->vstart->ops.lookup(pdata->vstart, pdata, firstcomp);
+}
+
+int vfs_mount_root(struct superblock *sb)
+{
+ /*
+ * Lookup the root vnode of this superblock.
+ * The root superblock has vnode number 0.
+ */
+ vfs_root.pivot = vfs_lookup_byvnum(sb, 0);
+ vfs_root.sb = sb;
+
+ return 0;
+}
+
diff --git a/conts/posix/fs0/tools/generate_bootdesc.py b/conts/posix/fs0/tools/generate_bootdesc.py
new file mode 100755
index 0000000..9761a6d
--- /dev/null
+++ b/conts/posix/fs0/tools/generate_bootdesc.py
@@ -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()
+
diff --git a/conts/posix/libposix/README b/conts/posix/libposix/README
new file mode 100644
index 0000000..bce1bcc
--- /dev/null
+++ b/conts/posix/libposix/README
@@ -0,0 +1,84 @@
+
+libposix
+
+Copyright (C) 2007 Bahadir Balban
+
+Despite the name, this is a library that supports only a small portion of posix
+functions.
+
+Note however, that unlike many other shallow POSIX implementations function
+listed below are backed by a real virtual memory subsystem and a virtual
+filesystem.
+
+Highest priority POSIX functions are:
+
+shmat
+shmget
+shmdt
+mmap
+munmap
+sbrk
+read
+readdir
+write
+lseek
+open
+close
+creat
+mkdir
+mknod
+link
+unlink
+fork
+clone
+execve
+getpid
+wait
+kill
+getenv
+setenv
+
+
+Currently supported functions are:
+
+shmat
+shmget
+shmdt
+mmap
+munmap
+read
+readdir
+write
+lseek
+open
+close
+creat
+mkdir
+mknod
+fork
+clone
+execve
+exit
+getpid
+
+
+Functions to be supported in the near future are:
+
+link
+unlink
+wait
+kill
+sbrk
+getenv
+setenv
+
+
+Other calls:
+pipe
+mount
+unmount
+swapon
+
+
+New ones will be added as needed.
+
diff --git a/conts/posix/libposix/SConscript b/conts/posix/libposix/SConscript
new file mode 100644
index 0000000..0ad256e
--- /dev/null
+++ b/conts/posix/libposix/SConscript
@@ -0,0 +1,16 @@
+# -*- mode: python; coding: utf-8; -*-
+
+# Codezero -- A Virtualization microkernel for embedded systems.
+#
+# Copyright © 2009 B Labs Ltd
+
+Import('env')
+
+e = env.Clone()
+e.Append(CPPPATH = ['include', 'include/posix'])
+e.Replace(CCFLAGS = ['-g', '-nostdlib', '-Wall', '-ffreestanding', '-std=gnu99'])
+
+objects = e.StaticObject(Glob('*.c'))
+libposix = e.StaticLibrary('posix', objects)
+
+Return('libposix')
diff --git a/conts/posix/libposix/SConstruct b/conts/posix/libposix/SConstruct
new file mode 100644
index 0000000..352c734
--- /dev/null
+++ b/conts/posix/libposix/SConstruct
@@ -0,0 +1,74 @@
+#
+# 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', '-std=gnu99', '-nostdlib', '-ffreestanding'],
+ LINKFLAGS = ['-nostdlib'],
+ CPPPATH = ['#include'],
+ 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)
+
+
diff --git a/conts/posix/libposix/chdir.c b/conts/posix/libposix/chdir.c
new file mode 100644
index 0000000..5169745
--- /dev/null
+++ b/conts/posix/libposix/chdir.c
@@ -0,0 +1,54 @@
+/*
+ * l4/posix glue for mkdir()
+ *
+ * Copyright (C) 2008 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include INC_GLUE(memory.h)
+
+static inline int l4_chdir(const char *pathname)
+{
+ int fd;
+
+ // write_mr(L4SYS_ARG0, (unsigned long)pathname);
+ copy_to_shpage((void *)pathname, 0, strlen(pathname) + 1);
+ write_mr(L4SYS_ARG0, (unsigned long)shared_page);
+
+ /* Call pager with shmget() request. Check ipc error. */
+ if ((fd = l4_sendrecv(VFS_TID, VFS_TID, L4_IPC_TAG_CHDIR)) < 0) {
+ print_err("%s: L4 IPC Error: %d.\n", __FUNCTION__, fd);
+ return fd;
+ }
+ /* Check if syscall itself was successful */
+ if ((fd = l4_get_retval()) < 0) {
+ print_err("%s: MKDIR Error: %d.\n", __FUNCTION__, fd);
+ return fd;
+ }
+ return fd;
+}
+
+int chdir(const char *pathname)
+{
+ int ret;
+
+ /* If error, return positive error code */
+ if ((ret = l4_chdir(pathname)) < 0) {
+ errno = -ret;
+ return -1;
+ }
+ /* else return value */
+ return ret;
+}
+
diff --git a/conts/posix/libposix/close.c b/conts/posix/libposix/close.c
new file mode 100644
index 0000000..2e4fc46
--- /dev/null
+++ b/conts/posix/libposix/close.c
@@ -0,0 +1,78 @@
+/*
+ * l4/posix glue for close() and fsync()
+ *
+ * Copyright (C) 2007 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include INC_GLUE(memory.h)
+#include
+
+static inline int l4_close(int fd)
+{
+ write_mr(L4SYS_ARG0, fd);
+
+ /* Call pager with close() request. Check ipc error. */
+ if ((fd = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_CLOSE)) < 0) {
+ print_err("%s: L4 IPC Error: %d.\n", __FUNCTION__, fd);
+ return fd;
+ }
+ /* Check if syscall itself was successful */
+ if ((fd = l4_get_retval()) < 0) {
+ print_err("%s: CLOSE Error: %d.\n", __FUNCTION__, fd);
+ return fd;
+ }
+ return fd;
+}
+
+int close(int fd)
+{
+ int ret = l4_close(fd);
+
+ /* If error, return positive error code */
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+
+ /* else return value */
+ return ret;
+}
+
+static inline int l4_fsync(int fd)
+{
+ write_mr(L4SYS_ARG0, fd);
+
+ /* Call pager with close() request. Check ipc error. */
+ if ((fd = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_FSYNC)) < 0) {
+ print_err("%s: L4 IPC Error: %d.\n", __FUNCTION__, fd);
+ return fd;
+ }
+ /* Check if syscall itself was successful */
+ if ((fd = l4_get_retval()) < 0) {
+ print_err("%s: CLOSE Error: %d.\n", __FUNCTION__, fd);
+ return fd;
+ }
+ return fd;
+}
+
+int fsync(int fd)
+{
+ int ret = l4_fsync(fd);
+
+ /* If error, return positive error code */
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+
+ /* else return value */
+ return ret;
+}
+
diff --git a/conts/posix/libposix/env.c b/conts/posix/libposix/env.c
new file mode 100644
index 0000000..69aabee
--- /dev/null
+++ b/conts/posix/libposix/env.c
@@ -0,0 +1,35 @@
+/*
+ * Environment accessor functions
+ *
+ * Copyright (C) 2008 Bahadir Balban
+ */
+#include
+#include
+#include
+
+char **__environ;
+
+/*
+ * Search for given name in name=value string pairs located
+ * in the environment segment, and return the pointer to value
+ * string.
+ */
+char *getenv(const char *name)
+{
+ char **envp = __environ;
+ int length;
+
+ if (!envp)
+ return 0;
+ length = strlen(name);
+
+ while(*envp) {
+ if (memcmp(name, *envp, length) == 0 &&
+ (*envp)[length] == '=')
+ return *envp + length + 1;
+ envp++;
+ }
+
+ return 0;
+}
+
diff --git a/conts/posix/libposix/errno.c b/conts/posix/libposix/errno.c
new file mode 100644
index 0000000..03800ec
--- /dev/null
+++ b/conts/posix/libposix/errno.c
@@ -0,0 +1,15 @@
+#include
+#include
+#include
+
+int errno_variable;
+
+void perror(const char *str)
+{
+ print_err("%s: %d\n", str, errno);
+}
+
+int *__errno_location(void)
+{
+ return &errno_variable;
+}
diff --git a/conts/posix/libposix/execve.c b/conts/posix/libposix/execve.c
new file mode 100644
index 0000000..a698c7d
--- /dev/null
+++ b/conts/posix/libposix/execve.c
@@ -0,0 +1,67 @@
+/*
+ * l4/posix glue for execve()
+ *
+ * Copyright (C) 2007 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include INC_GLUE(memory.h)
+#include
+
+
+struct sys_execve_args {
+ char *path;
+ char **argv;
+ char **envp;
+};
+
+static inline int l4_execve(const char *pathname, char *const argv[], char *const envp[])
+{
+ int err = 0;
+
+ write_mr(L4SYS_ARG0, (unsigned long)pathname);
+ write_mr(L4SYS_ARG1, (unsigned long)argv);
+ write_mr(L4SYS_ARG2, (unsigned long)envp);
+
+
+ /* Call pager with open() request. Check ipc error. */
+ if ((err = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_EXECVE)) < 0) {
+ print_err("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
+ return err;
+ }
+ /* Check if syscall itself was successful */
+ if ((err = l4_get_retval()) < 0) {
+ print_err("%s: OPEN Error: %d.\n", __FUNCTION__, err);
+ return err;
+ }
+
+ return err;
+}
+
+int execve(const char *pathname, char *const argv[], char *const envp[])
+{
+ int ret;
+
+ ret = l4_execve(pathname, argv, envp);
+
+ /* If error, return positive error code */
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ /* else return value */
+ return ret;
+
+}
+
diff --git a/conts/posix/libposix/exit.c b/conts/posix/libposix/exit.c
new file mode 100644
index 0000000..5708360
--- /dev/null
+++ b/conts/posix/libposix/exit.c
@@ -0,0 +1,27 @@
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+static inline void __attribute__ ((noreturn)) l4_exit(int status)
+{
+ int ret;
+
+ write_mr(L4SYS_ARG0, status);
+
+ /* Call pager with exit() request and block on its receive phase */
+ ret = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_EXIT);
+
+ /* This call should not fail or return */
+ print_err("%s: L4 IPC returned: %d.\n", __FUNCTION__, ret);
+ BUG();
+}
+
+void __attribute__ ((noreturn)) _exit(int status)
+{
+ l4_exit(status);
+}
+
diff --git a/conts/posix/libposix/fork.c b/conts/posix/libposix/fork.c
new file mode 100644
index 0000000..4072bf8
--- /dev/null
+++ b/conts/posix/libposix/fork.c
@@ -0,0 +1,90 @@
+/*
+ * l4/posix glue for fork()
+ *
+ * Copyright (C) 2008 Bahadir Balban
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include INC_GLUE(memory.h)
+#include
+#include
+
+static inline int l4_fork(void)
+{
+ int err;
+
+ /* Call pager with open() request. Check ipc error. */
+ if ((err = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_FORK)) < 0) {
+ print_err("%s: L4 IPC Error: %d.\n", __FUNCTION__, err);
+ return err;
+ }
+ /* Check if syscall itself was successful */
+ if ((err = l4_get_retval()) < 0) {
+ print_err("%s: OPEN Error: %d.\n", __FUNCTION__, err);
+ return err;
+ }
+ return err;
+}
+
+int fork(void)
+{
+ int ret = l4_fork();
+
+ /* If error, return positive error code */
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+
+ /*
+ * If we're a child, we need to initialise the default
+ * shared page via libposix_init()
+ */
+ if (ret == 0)
+ shared_page_init();
+
+ return ret;
+}
+
+extern int arch_clone(l4id_t to, l4id_t from, unsigned int flags);
+
+int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...)
+{
+ /* Set up the child stack */
+ unsigned int *stack = child_stack;
+ int ret;
+
+ /* First word of new stack is arg */
+ stack[-1] = (unsigned long)arg;
+
+ /* Second word of new stack is function address */
+ stack[-2] = (unsigned long)fn;
+
+ /* Write the tag */
+ l4_set_tag(L4_IPC_TAG_CLONE);
+
+ /* Write the args as in usual ipc */
+ write_mr(L4SYS_ARG0, (unsigned long)child_stack);
+ write_mr(L4SYS_ARG1, flags);
+
+ /* Perform an ipc but with different return logic. See implementation. */
+ if ((ret = arch_clone(PAGER_TID, PAGER_TID, 0)) < 0) {
+ print_err("%s: L4 IPC Error: %d.\n", __FUNCTION__, ret);
+ return ret;
+ }
+
+ if ((ret = l4_get_retval()) < 0) {
+ print_err("%s: CLONE Error: %d.\n", __FUNCTION__, ret);
+ return ret;
+ }
+ return ret;
+}
+
+
+
diff --git a/conts/posix/libposix/getpid.c b/conts/posix/libposix/getpid.c
new file mode 100644
index 0000000..d4f9287
--- /dev/null
+++ b/conts/posix/libposix/getpid.c
@@ -0,0 +1,11 @@
+
+#include
+#include
+#include
+#include
+#include
+
+pid_t getpid(void)
+{
+ return self_tid();
+}
diff --git a/conts/posix/libposix/include/libposix.h b/conts/posix/libposix/include/libposix.h
new file mode 100644
index 0000000..d0f05db
--- /dev/null
+++ b/conts/posix/libposix/include/libposix.h
@@ -0,0 +1,13 @@
+#ifndef __LIBPOSIX_H__
+#define __LIBPOSIX_H__
+
+/* Abort debugging conditions */
+// #define LIBPOSIX_ERROR_MESSAGES
+#if defined (LIBPOSIX_ERROR_MESSAGES)
+#define print_err(...) printf(__VA_ARGS__)
+#else
+#define print_err(...)
+#endif
+
+
+#endif /* __LIBPOSIX_H__ */
diff --git a/conts/posix/libposix/include/posix/_lfs_64.h b/conts/posix/libposix/include/posix/_lfs_64.h
new file mode 100644
index 0000000..3e56bbf
--- /dev/null
+++ b/conts/posix/libposix/include/posix/_lfs_64.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+#include
+
+#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
diff --git a/conts/posix/libposix/include/posix/a.out.h b/conts/posix/libposix/include/posix/a.out.h
new file mode 100644
index 0000000..d963de7
--- /dev/null
+++ b/conts/posix/libposix/include/posix/a.out.h
@@ -0,0 +1,5 @@
+#ifdef _LIBC
+# include_next
+#else
+# include
+#endif
diff --git a/conts/posix/libposix/include/posix/alloca.h b/conts/posix/libposix/include/posix/alloca.h
new file mode 100644
index 0000000..b4fc317
--- /dev/null
+++ b/conts/posix/libposix/include/posix/alloca.h
@@ -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
+
+#define __need_size_t
+#include
+
+__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 */
diff --git a/conts/posix/libposix/include/posix/ar.h b/conts/posix/libposix/include/posix/ar.h
new file mode 100644
index 0000000..5d157ec
--- /dev/null
+++ b/conts/posix/libposix/include/posix/ar.h
@@ -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
+
+/* 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 "!\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 */
diff --git a/conts/posix/libposix/include/posix/arpa/ftp.h b/conts/posix/libposix/include/posix/arpa/ftp.h
new file mode 100644
index 0000000..e5b340d
--- /dev/null
+++ b/conts/posix/libposix/include/posix/arpa/ftp.h
@@ -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 */
diff --git a/conts/posix/libposix/include/posix/arpa/inet.h b/conts/posix/libposix/include/posix/arpa/inet.h
new file mode 100644
index 0000000..fe3373b
--- /dev/null
+++ b/conts/posix/libposix/include/posix/arpa/inet.h
@@ -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
+#include /* 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 */
diff --git a/conts/posix/libposix/include/posix/arpa/nameser.h b/conts/posix/libposix/include/posix/arpa/nameser.h
new file mode 100644
index 0000000..496c8db
--- /dev/null
+++ b/conts/posix/libposix/include/posix/arpa/nameser.h
@@ -0,0 +1,557 @@
+/*
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * $BINDId: nameser.h,v 8.37 2000/03/30 21:16:49 vixie Exp $
+ */
+
+#ifndef _ARPA_NAMESER_H_
+#define _ARPA_NAMESER_H_
+
+#define BIND_4_COMPAT
+
+#include
+#if (!defined(BSD)) || (BSD < 199306)
+# include