Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ HelenOS.config	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -88,4 +88,5 @@
 @ "tmpfs" TMPFS image
 @ "fat" FAT16 image
+@ "ext2fs" EXT2 image
 ! RDFMT (choice)
 
Index: boot/Makefile
===================================================================
--- boot/Makefile	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ boot/Makefile	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -50,4 +50,7 @@
 	$(MKFAT) 1048576 $(DIST_PATH) $@
 endif
+ifeq ($(RDFMT),ext2fs)
+	$(MKEXT2) 1048576 $(DIST_PATH) $@
+endif
 
 build_dist: clean_dist
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ boot/Makefile.common	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -56,4 +56,5 @@
 MKTMPFS = $(TOOLS_PATH)/mktmpfs.py
 MKFAT = $(TOOLS_PATH)/mkfat.py
+MKEXT2 = $(TOOLS_PATH)/mkext2.py
 MKUIMAGE = $(TOOLS_PATH)/mkuimage.py
 
@@ -82,4 +83,8 @@
 ifeq ($(RDFMT),fat)
 	INIT_TASKS += $(USPACE_PATH)/srv/fs/fat/fat
+endif
+
+ifeq ($(RDFMT),ext2fs)
+	INIT_TASKS += $(USPACE_PATH)/srv/fs/ext2fs/ext2fs
 endif
 
Index: kernel/generic/include/lib/elf.h
===================================================================
--- kernel/generic/include/lib/elf.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ kernel/generic/include/lib/elf.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -42,150 +42,144 @@
  * current ELF version
  */
-#define EV_CURRENT  1
+#define EV_CURRENT	1
 
 /**
  * ELF types
  */
-#define ET_NONE    0       /* No type */
-#define ET_REL     1       /* Relocatable file */
-#define ET_EXEC    2       /* Executable */
-#define ET_DYN     3       /* Shared object */
-#define ET_CORE    4       /* Core */
-#define ET_LOPROC  0xff00  /* Processor specific */
-#define ET_HIPROC  0xffff  /* Processor specific */
+#define ET_NONE		0	/* No type */
+#define ET_REL		1	/* Relocatable file */
+#define ET_EXEC		2	/* Executable */
+#define ET_DYN		3	/* Shared object */
+#define ET_CORE		4	/* Core */
+#define ET_LOPROC	0xff00	/* Processor specific */
+#define ET_HIPROC	0xffff	/* Processor specific */
 
 /**
  * ELF machine types
  */
-#define EM_NO           0   /* No machine */
-#define EM_SPARC        2   /* SPARC */
-#define EM_386          3   /* i386 */
-#define EM_MIPS         8   /* MIPS RS3000 */
-#define EM_MIPS_RS3_LE  10  /* MIPS RS3000 LE */
-#define EM_PPC          20  /* PPC32 */
-#define EM_PPC64        21  /* PPC64 */
-#define EM_ARM          40  /* ARM */
-#define EM_SPARCV9      43  /* SPARC64 */
-#define EM_IA_64        50  /* IA-64 */
-#define EM_X86_64       62  /* AMD64/EMT64 */
+#define EM_NO		0	/* No machine */
+#define EM_SPARC	2	/* SPARC */
+#define EM_386		3	/* i386 */
+#define EM_MIPS		8	/* MIPS RS3000 */
+#define EM_MIPS_RS3_LE	10	/* MIPS RS3000 LE */
+#define EM_PPC		20	/* PPC32 */
+#define EM_PPC64	21	/* PPC64 */
+#define EM_ARM		40	/* ARM */
+#define EM_SPARCV9	43	/* SPARC64 */
+#define EM_IA_64	50	/* IA-64 */
+#define EM_X86_64	62	/* AMD64/EMT64 */
 
 /**
  * ELF identification indexes
  */
-#define EI_MAG0        0
-#define EI_MAG1        1
-#define EI_MAG2        2
-#define EI_MAG3        3
-#define EI_CLASS       4   /* File class */
-#define EI_DATA        5   /* Data encoding */
-#define EI_VERSION     6   /* File version */
-#define EI_OSABI       7
-#define EI_ABIVERSION  8
-#define EI_PAD         9   /* Start of padding bytes */
-#define EI_NIDENT      16  /* ELF identification table size */
+#define EI_MAG0		0
+#define EI_MAG1		1
+#define EI_MAG2		2
+#define EI_MAG3		3
+#define EI_CLASS	4		/* File class */
+#define EI_DATA		5		/* Data encoding */
+#define EI_VERSION	6		/* File version */
+#define EI_OSABI	7
+#define EI_ABIVERSION	8
+#define EI_PAD		9		/* Start of padding bytes */
+#define EI_NIDENT	16		/* ELF identification table size */
 
 /**
  * ELF magic number
  */
-#define ELFMAG0  0x7f
-#define ELFMAG1  'E'
-#define ELFMAG2  'L'
-#define ELFMAG3  'F'
+#define ELFMAG0		0x7f
+#define ELFMAG1		'E'
+#define ELFMAG2		'L'
+#define ELFMAG3		'F'
 
 /**
  * ELF file classes
  */
-#define ELFCLASSNONE  0
-#define ELFCLASS32    1
-#define ELFCLASS64    2
+#define ELFCLASSNONE	0
+#define ELFCLASS32	1
+#define ELFCLASS64	2
 
 /**
  * ELF data encoding types
  */
-#define ELFDATANONE  0
-#define ELFDATA2LSB  1  /* Least significant byte first (little endian) */
-#define ELFDATA2MSB  2  /* Most signigicant byte first (big endian) */
-
-/**
- * ELF error return codes
- */
-#define EE_OK             0  /* No error */
-#define EE_INVALID        1  /* Invalid ELF image */
-#define EE_MEMORY         2  /* Cannot allocate address space */
-#define EE_INCOMPATIBLE   3  /* ELF image is not compatible with current architecture */
-#define EE_UNSUPPORTED    4  /* Non-supported ELF (e.g. dynamic ELFs) */
-#define EE_LOADER         5  /* The image is actually a program loader */
-#define EE_IRRECOVERABLE  6
+#define ELFDATANONE	0
+#define ELFDATA2LSB	1		/* Least significant byte first (little endian) */
+#define ELFDATA2MSB	2		/* Most signigicant byte first (big endian) */
 
 /**
  * ELF section types
  */
-#define SHT_NULL      0
-#define SHT_PROGBITS  1
-#define SHT_SYMTAB    2
-#define SHT_STRTAB    3
-#define SHT_RELA      4
-#define SHT_HASH      5
-#define SHT_DYNAMIC   6
-#define SHT_NOTE      7
-#define SHT_NOBITS    8
-#define SHT_REL       9
-#define SHT_SHLIB     10
-#define SHT_DYNSYM    11
-#define SHT_LOOS      0x60000000
-#define SHT_HIOS      0x6fffffff
-#define SHT_LOPROC    0x70000000
-#define SHT_HIPROC    0x7fffffff
-#define SHT_LOUSER    0x80000000
-#define SHT_HIUSER    0xffffffff
+#define SHT_NULL		0
+#define SHT_PROGBITS		1
+#define SHT_SYMTAB		2
+#define SHT_STRTAB		3
+#define SHT_RELA		4
+#define SHT_HASH		5
+#define SHT_DYNAMIC		6
+#define SHT_NOTE		7
+#define SHT_NOBITS		8
+#define SHT_REL			9
+#define SHT_SHLIB		10
+#define SHT_DYNSYM		11
+#define SHT_LOOS		0x60000000
+#define SHT_HIOS		0x6fffffff
+#define SHT_LOPROC		0x70000000
+#define SHT_HIPROC		0x7fffffff
+#define SHT_LOUSER		0x80000000
+#define SHT_HIUSER		0xffffffff
 
 /**
  * ELF section flags
  */
-#define SHF_WRITE      0x1
-#define SHF_ALLOC      0x2
-#define SHF_EXECINSTR  0x4
-#define SHF_TLS        0x400
-#define SHF_MASKPROC   0xf0000000
+#define SHF_WRITE		0x1 
+#define SHF_ALLOC		0x2
+#define SHF_EXECINSTR		0x4
+#define SHF_TLS			0x400
+#define SHF_MASKPROC		0xf0000000
+
+/** Macros for decomposing elf_symbol.st_info into binging and type */
+#define ELF_ST_BIND(i)		((i) >> 4)
+#define ELF_ST_TYPE(i)		((i) & 0x0f)
+#define ELF_ST_INFO(b, t)	(((b) << 4) + ((t) & 0x0f))
 
 /**
  * Symbol binding
  */
-#define STB_LOCAL   0
-#define STB_GLOBAL  1
-#define STB_WEAK    2
-#define STB_LOPROC  13
-#define STB_HIPROC  15
+#define STB_LOCAL		0
+#define STB_GLOBAL		1
+#define STB_WEAK		2
+#define STB_LOPROC		13
+#define STB_HIPROC		15
 
 /**
  * Symbol types
  */
-#define STT_NOTYPE   0
-#define STT_OBJECT   1
-#define STT_FUNC     2
-#define STT_SECTION  3
-#define STT_FILE     4
-#define STT_LOPROC   13
-#define STT_HIPROC   15
+#define STT_NOTYPE		0
+#define STT_OBJECT		1
+#define STT_FUNC		2
+#define STT_SECTION		3
+#define STT_FILE		4
+#define STT_LOPROC		13
+#define STT_HIPROC		15
 
 /**
  * Program segment types
  */
-#define PT_NULL     0
-#define PT_LOAD     1
-#define PT_DYNAMIC  2
-#define PT_INTERP   3
-#define PT_NOTE     4
-#define PT_SHLIB    5
-#define PT_PHDR     6
-#define PT_LOPROC   0x70000000
-#define PT_HIPROC   0x7fffffff
+#define PT_NULL			0
+#define PT_LOAD			1
+#define PT_DYNAMIC		2
+#define PT_INTERP		3
+#define PT_NOTE			4
+#define PT_SHLIB		5
+#define PT_PHDR			6
+#define PT_LOPROC		0x70000000
+#define PT_HIPROC		0x7fffffff
 
 /**
  * Program segment attributes.
  */
-#define PF_X  1
-#define PF_W  2
-#define PF_R  4
+#define PF_X	1
+#define PF_W	2
+#define PF_R	4
 
 /**
@@ -195,5 +189,4 @@
  * ELF object file specifications. They are the only types used
  * in ELF header.
- *
  */
 typedef uint64_t elf_xword;
@@ -207,5 +200,4 @@
  *
  * These types are specific for 32-bit format.
- *
  */
 typedef uint32_t elf32_addr;
@@ -216,5 +208,4 @@
  *
  * These types are specific for 64-bit format.
- *
  */
 typedef uint64_t elf64_addr;
@@ -238,5 +229,4 @@
 	elf_half e_shstrndx;
 };
-
 struct elf64_header {
 	uint8_t e_ident[EI_NIDENT];
@@ -256,5 +246,5 @@
 };
 
-/**
+/*
  * ELF segment header.
  * Segments headers are also known as program headers.
@@ -270,5 +260,4 @@
 	elf_word p_align;
 };
-
 struct elf64_segment_header {
 	elf_word p_type;
@@ -282,5 +271,5 @@
 };
 
-/**
+/*
  * ELF section header
  */
@@ -297,5 +286,4 @@
 	elf_word sh_entsize;
 };
-
 struct elf64_section_header {
 	elf_word sh_name;
@@ -311,5 +299,5 @@
 };
 
-/**
+/*
  * ELF symbol table entry
  */
@@ -322,5 +310,4 @@
 	elf_half st_shndx;
 };
-
 struct elf64_symbol {
 	elf_word st_name;
@@ -332,4 +319,18 @@
 };
 
+/*
+ * ELF note segment entry
+ */
+struct elf32_note {
+	elf_word namesz;
+	elf_word descsz;
+	elf_word type;
+};
+struct elf64_note {
+	elf_xword namesz;
+	elf_xword descsz;
+	elf_xword type;
+};
+
 #ifdef __32_BITS__
 typedef struct elf32_header elf_header_t;
@@ -337,6 +338,6 @@
 typedef struct elf32_section_header elf_section_header_t;
 typedef struct elf32_symbol elf_symbol_t;
+typedef struct elf32_note elf_note_t;
 #endif
-
 #ifdef __64_BITS__
 typedef struct elf64_header elf_header_t;
@@ -344,7 +345,6 @@
 typedef struct elf64_section_header elf_section_header_t;
 typedef struct elf64_symbol elf_symbol_t;
+typedef struct elf64_note elf_note_t;
 #endif
-
-extern const char *elf_error(unsigned int rc);
 
 /** Interpreter string used to recognize the program loader */
Index: kernel/generic/include/lib/elf_load.h
===================================================================
--- kernel/generic/include/lib/elf_load.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ kernel/generic/include/lib/elf_load.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2006 Sergey Bondari
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup generic
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_ELF_LOAD_H_
+#define KERN_ELF_LOAD_H_
+
+#include <arch/elf.h>
+#include <typedefs.h>
+
+/**
+ * ELF error return codes
+ */
+#define EE_OK			0	/* No error */
+#define EE_INVALID		1	/* Invalid ELF image */
+#define	EE_MEMORY		2	/* Cannot allocate address space */
+#define EE_INCOMPATIBLE		3	/* ELF image is not compatible with current architecture */
+#define EE_UNSUPPORTED		4	/* Non-supported ELF (e.g. dynamic ELFs) */
+#define EE_LOADER		5	/* The image is actually a program loader. */
+#define EE_IRRECOVERABLE	6
+
+/**
+ * This flags is passed when running the loader, otherwise elf_load()
+ * would return with a EE_LOADER error code.
+ *
+ */
+#define ELD_F_NONE    0
+#define ELD_F_LOADER  1
+
+extern unsigned int elf_load(elf_header_t *, as_t *, unsigned int);
+extern const char *elf_error(unsigned int rc);
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/mm/as.h
===================================================================
--- kernel/generic/include/mm/as.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ kernel/generic/include/mm/as.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -307,14 +307,4 @@
 extern mem_backend_t phys_backend;
 
-/**
- * This flags is passed when running the loader, otherwise elf_load()
- * would return with a EE_LOADER error code.
- *
- */
-#define ELD_F_NONE    0
-#define ELD_F_LOADER  1
-
-extern unsigned int elf_load(elf_header_t *, as_t *, unsigned int);
-
 /* Address space area related syscalls. */
 extern sysarg_t sys_as_area_create(uintptr_t, size_t, unsigned int);
Index: kernel/generic/src/lib/elf.c
===================================================================
--- kernel/generic/src/lib/elf.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ kernel/generic/src/lib/elf.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -47,4 +47,6 @@
 #include <macros.h>
 #include <arch.h>
+
+#include <lib/elf_load.h>
 
 static const char *error_codes[] = {
Index: kernel/generic/src/proc/program.c
===================================================================
--- kernel/generic/src/proc/program.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ kernel/generic/src/proc/program.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -48,5 +48,5 @@
 #include <ipc/ipcrsc.h>
 #include <security/cap.h>
-#include <lib/elf.h>
+#include <lib/elf_load.h>
 #include <errno.h>
 #include <print.h>
Index: tools/imgutil.py
===================================================================
--- tools/imgutil.py	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ tools/imgutil.py	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2008 Martin Decky
+# Copyright (c) 2011 Martin Sucha
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - 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.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+#
+
+"""
+Utilities for filesystem image creators
+"""
+
+import os
+import stat
+
+exclude_names = set(['.svn', '.bzr'])
+
+def align_up(size, alignment):
+	"Return size aligned up to alignment"
+	
+	if (size % alignment == 0):
+		return size
+	
+	return ((size // alignment) + 1) * alignment
+
+def count_up(size, alignment):
+	"Return units necessary to fit the size"
+	
+	if (size % alignment == 0):
+		return (size // alignment)
+	
+	return ((size // alignment) + 1)
+
+def num_of_trailing_bin_zeros(num):
+	"Return number of trailing zeros in binary representation"
+	
+	i = 0
+	if (num == 0): raise ValueError()
+	while num & 1 == 0:
+		i += 1
+		num = num >> 1
+	return i
+
+def get_bit(number, n):
+	"Return True if n-th least-significant bit is set in the given number"
+	
+	return bool((number >> n) & 1)
+
+def set_bit(number, n):
+	"Return the number with n-th least-significant bit set"
+	
+	return number | (1 << n)
+
+class ItemToPack:
+	"Stores information about one directory item to be added to the image"
+	
+	def __init__(self, parent, name):
+		self.parent = parent
+		self.name = name
+		self.path = os.path.join(parent, name)
+		self.stat = os.stat(self.path)
+		self.is_dir = stat.S_ISDIR(self.stat.st_mode)
+		self.is_file = stat.S_ISREG(self.stat.st_mode)
+		self.size = self.stat.st_size
+
+def listdir_items(path):
+	"Return a list of items to be packed inside a fs image"
+	
+	for name in os.listdir(path):
+		if name in exclude_names:
+			continue
+		item = ItemToPack(path, name)
+		if not (item.is_dir or item.is_file):
+			continue
+		yield item
+
+def chunks(item, chunk_size):
+	"Iterate contents of a file in chunks of a given size"
+	
+	inf = open(item.path, 'rb')
+	rd = 0
+	while (rd < item.size):
+		data = bytes(inf.read(chunk_size))
+		yield data
+		rd += len(data)
+	inf.close()
Index: tools/mkext2.py
===================================================================
--- tools/mkext2.py	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ tools/mkext2.py	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,676 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2011 Martin Sucha
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - 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.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+#
+
+"""
+EXT2 creator
+"""
+
+import sys
+import os
+import xstruct
+import array
+import time
+import uuid
+from imgutil import *
+
+GDE_SIZE = 32
+
+STRUCT_DIR_ENTRY_HEAD = """little:
+	uint32_t inode       /* inode number */
+	uint16_t skip        /* byte offset to the next record */
+	uint8_t  name_length /* file attributes */
+	uint8_t  inode_type  /* type of the referenced inode */
+"""
+
+STRUCT_SUPERBLOCK = """little:
+	uint32_t total_inode_count    /* Total number of inodes */
+	uint32_t total_block_count    /* Total number of blocks */
+	uint32_t reserved_block_count /* Total number of reserved blocks */
+	uint32_t free_block_count     /* Total number of free blocks */
+	uint32_t free_inode_count     /* Total number of free inodes */
+	uint32_t first_block          /* Block containing the superblock */
+	uint32_t block_size_log2      /* log_2(block_size) */
+	int32_t  fragment_size_log2   /* log_2(fragment size) */
+	uint32_t blocks_per_group     /* Number of blocks in one block group */
+	uint32_t fragments_per_group  /* Number of fragments per block group */
+	uint32_t inodes_per_group     /* Number of inodes per block group */
+	uint32_t mount_time           /* Time when the filesystem was last mounted */
+	uint32_t write_time           /* Time when the filesystem was last written */
+	uint16_t mount_count          /* Mount count since last full filesystem check */
+	uint16_t max_mount_count      /* Number of mounts after which the fs must be checked */
+	uint16_t magic                /* Magic value */
+	uint16_t state                /* State (mounted/unmounted) */
+	uint16_t error_behavior       /* What to do when errors are encountered */
+	uint16_t rev_minor            /* Minor revision level */
+	uint32_t last_check_time      /* Unix time of last fs check */
+	uint32_t max_check_interval   /* Max unix time interval between checks */
+	uint32_t os                   /* OS that created the filesystem */
+	uint32_t rev_major            /* Major revision level */
+	padding[4] /* default reserved uid and gid */
+	
+	/* Following is for ext2 revision 1 only */
+	uint32_t first_inode
+	uint16_t inode_size
+	uint16_t block_group_number /* Block group where this SB is stored */
+	uint32_t features_compatible
+	uint32_t features_incompatible
+	uint32_t features_read_only
+	char     uuid[16]
+	char     volume_name[16]
+"""
+
+STRUCT_BLOCK_GROUP_DESCRIPTOR = """little:
+	uint32_t block_bitmap_block      /* Block ID for block bitmap */
+	uint32_t inode_bitmap_block      /* Block ID for inode bitmap */
+	uint32_t inode_table_first_block /* Block ID of first block of inode table */
+	uint16_t free_block_count        /* Count of free blocks */
+	uint16_t free_inode_count        /* Count of free inodes */
+	uint16_t directory_inode_count   /* Number of inodes allocated to directories */
+"""
+
+STRUCT_INODE = """little:
+	uint16_t mode
+	uint16_t user_id
+	uint32_t size
+	uint32_t access_time
+	uint32_t creation_time
+	uint32_t modification_time
+	uint32_t deletion_time
+	uint16_t group_id
+	uint16_t usage_count /* Hard link count, when 0 the inode is to be freed */
+	uint32_t reserved_512_blocks /* Size of this inode in 512-byte blocks */
+	uint32_t flags
+	padding[4]
+	uint32_t direct_blocks[12] /* Direct block ids stored in this inode */
+	uint32_t indirect_blocks[3]
+	uint32_t version
+	uint32_t file_acl
+	uint32_t size_high /* For regular files in version >= 1, dir_acl if dir */
+	padding[6]
+	uint16_t mode_high /* Hurd only */
+	uint16_t user_id_high /* Linux/Hurd only */
+	uint16_t group_id_high /* Linux/Hurd only */
+"""
+
+# The following is here to handle byte-order conversion in indirect block lookups
+STRUCT_BLOCK_REFERENCE = """little:
+	uint32_t block_id /* Referenced block ID */
+"""
+
+class Filesystem:	
+	def __init__(self, filename, block_groups, blocks_per_group, inodes_per_group, block_size, inode_size, reserved_inode_count):
+		"Initialize the filesystem writer"
+		
+		outf = open(filename, "w+b")
+		# Set the correct size of the image, so that we can read arbitrary position
+		outf.truncate(block_size * blocks_per_group * block_groups)
+		self.outf = outf
+		self.uuid = uuid.uuid4()
+		self.block_size = block_size
+		self.inode_size = inode_size
+		self.block_groups = block_groups
+		self.blocks_per_group = blocks_per_group
+		self.inodes_per_group = inodes_per_group
+		self.reserved_inode_count = reserved_inode_count
+		self.gdt_blocks = count_up(block_groups * GDE_SIZE, block_size)
+		self.inode_table_blocks_per_group = (inodes_per_group * inode_size) // block_size
+		self.inode_bitmap_blocks_per_group = count_up(inodes_per_group // 8, block_size)
+		self.block_bitmap_blocks_per_group = count_up(blocks_per_group // 8, block_size)
+		self.total_block_count = self.blocks_per_group * self.block_groups
+		self.total_inode_count = self.inodes_per_group * self.block_groups
+		self.inode_table_blocks = count_up(self.total_inode_count * inode_size, block_size)
+		self.inodes = {}
+		self.superblock_at_block = 2047 // block_size
+		self.block_ids_per_block = self.block_size // 4
+		self.indirect_limits = [12, None, None, None]
+		self.indirect_blocks_per_level = [1, None, None, None]
+		for i in range(1,4):
+			self.indirect_blocks_per_level[i] = self.indirect_blocks_per_level[i-1] * self.block_ids_per_block
+			self.indirect_limits[i] = self.indirect_limits[i-1] + self.indirect_blocks_per_level[i]
+		self.block_allocator = Allocator(0, self.total_block_count)
+		self.inode_allocator = Allocator(1, self.total_inode_count)
+		self.init_gdt()
+		# Set the callbacks after GDT has been initialized
+		self.block_allocator.mark_cb = self.mark_block_cb
+		self.inode_allocator.mark_cb = self.mark_inode_cb
+		self.block_allocator.mark_used_all(range(self.superblock_at_block))
+		self.inode_allocator.mark_used_all(range(1, self.reserved_inode_count + 1))
+		self.root_inode = Inode(self, 2, Inode.TYPE_DIR)
+		self.gdt[0].directory_inode_count += 1
+		self.lost_plus_found = Inode(self, self.inode_allocator.alloc(directory=True), Inode.TYPE_DIR)
+		lpf_dir = DirWriter(self.lost_plus_found)
+		lpf_dir.add(self.lost_plus_found.as_dirent('.'))
+		lpf_dir.add(self.root_inode.as_dirent('..'))
+		lpf_dir.finish()
+	
+	def init_gdt(self):
+		"Initialize block group descriptor table"
+		
+		self.superblock_positions = []
+		self.gdt = []
+		consumed_blocks_per_group = (1 + self.gdt_blocks +
+			    self.inode_bitmap_blocks_per_group +
+			    self.block_bitmap_blocks_per_group +
+			    self.inode_table_blocks_per_group)
+		initial_free_blocks = self.blocks_per_group - consumed_blocks_per_group
+		for bg in range(self.block_groups):
+			base = bg * self.blocks_per_group
+			if (bg == 0):
+				base = self.superblock_at_block
+				self.superblock_positions.append(1024)
+			else:
+				self.superblock_positions.append(base * self.block_size)
+			self.block_allocator.mark_used_all(range(base, base+consumed_blocks_per_group))
+			pos = base + 1 + self.gdt_blocks
+			gde = xstruct.create(STRUCT_BLOCK_GROUP_DESCRIPTOR)
+			gde.block_bitmap_block = pos
+			pos += self.block_bitmap_blocks_per_group
+			gde.inode_bitmap_block = pos
+			pos += self.inode_bitmap_blocks_per_group
+			gde.inode_table_first_block = pos
+			gde.free_block_count = initial_free_blocks
+			gde.free_inode_count = self.inodes_per_group
+			gde.directory_inode_count = 0
+			self.gdt.append(gde)
+	
+	def mark_block_cb(self, block):
+		"Called after a block has been allocated"
+		
+		self.gdt[block // self.blocks_per_group].free_block_count -= 1
+	
+	def mark_inode_cb(self, index, directory=False):
+		"Called after an inode has been allocated"
+		
+		index -= 1
+		gde = self.gdt[index // self.inodes_per_group]
+		gde.free_inode_count -= 1
+		if directory:
+			gde.directory_inode_count += 1		
+	
+	def seek_to_block(self, block, offset=0):
+		"Seek to offset bytes after the start of the given block"
+		
+		if offset < 0 or offset > self.block_size:
+			raise Exception("Invalid in-block offset")
+		self.outf.seek(block * self.block_size + offset)
+	
+	def seek_to_inode(self, index):
+		"Seek to the start of the inode structure for the inode number index"
+		
+		index -= 1
+		if index < 0:
+			raise Exception("Invalid inode number")
+		gde = self.gdt[index // self.inodes_per_group]
+		base_block = gde.inode_table_first_block
+		offset = (index % self.inodes_per_group) * self.inode_size
+		block = base_block + (offset // self.block_size)
+		self.seek_to_block(block, offset % self.block_size)	
+	
+	def subtree_add(self, inode, parent_inode, dirpath, is_root=False):
+		"Recursively add files to the filesystem"
+		
+		dir_writer = DirWriter(inode)	
+		dir_writer.add(inode.as_dirent('.'))
+		dir_writer.add(parent_inode.as_dirent('..'))
+		
+		if is_root:
+			dir_writer.add(self.lost_plus_found.as_dirent('lost+found'))
+
+		for item in listdir_items(dirpath):
+			newidx = self.inode_allocator.alloc(directory = item.is_dir)
+			if item.is_file:
+				child_inode = Inode(self, newidx, Inode.TYPE_FILE)
+				for data in chunks(item, self.block_size):
+					child_inode.write(data)
+			elif item.is_dir:
+				child_inode = Inode(self, newidx, Inode.TYPE_DIR)
+				self.subtree_add(child_inode, inode, item.path)
+		
+			dir_writer.add(child_inode.as_dirent(item.name))
+			self.write_inode(child_inode)
+
+		dir_writer.finish()
+	
+	def write_inode(self, inode):
+		"Write inode information into the inode table"
+		
+		self.seek_to_inode(inode.index)
+		self.outf.write(inode.pack())
+
+	def write_gdt(self):
+		"Write group descriptor table at the current file position"
+		
+		for gde in self.gdt:
+			data = bytes(gde.pack())
+			self.outf.write(data)
+			self.outf.seek(GDE_SIZE-len(data), os.SEEK_CUR)
+	
+	def write_superblock(self, block_group):
+		"Write superblock at the current position"
+		
+		sb = xstruct.create(STRUCT_SUPERBLOCK)
+		sb.total_inode_count = self.total_inode_count
+		sb.total_block_count = self.total_block_count
+		sb.reserved_block_count = 0
+		sb.free_block_count = self.block_allocator.free
+		sb.free_inode_count = self.inode_allocator.free
+		sb.first_block = self.superblock_at_block
+		sb.block_size_log2 = num_of_trailing_bin_zeros(self.block_size) - 10
+		sb.fragment_size_log2 = sb.block_size_log2
+		sb.blocks_per_group = self.blocks_per_group
+		sb.fragments_per_group = self.blocks_per_group
+		sb.inodes_per_group = self.inodes_per_group
+		curtime = int(time.time())
+		sb.mount_time = curtime
+		sb.write_time = curtime
+		sb.mount_count = 0
+		sb.max_mount_count = 21
+		sb.magic = 0xEF53
+		sb.state = 5 # clean
+		sb.error_behavior = 1 # continue on errors
+		sb.rev_minor = 0
+		sb.last_check_time = curtime
+		sb.max_check_interval = 15552000 # 6 months
+		sb.os = 0 # Linux
+		sb.rev_major = 1
+		sb.first_inode = self.reserved_inode_count + 1
+		sb.inode_size = self.inode_size
+		sb.block_group_number = block_group
+		sb.features_compatible = 0
+		sb.features_incompatible = 2 # filetype
+		sb.features_read_only = 0
+		sb.uuid = self.uuid.bytes_le
+		sb.volume_name = 'HelenOS rdimage\0'
+		self.outf.write(bytes(sb.pack()))
+	
+	def write_all_metadata(self):
+		"Write superblocks, block group tables, block and inode bitmaps"
+		
+		bbpg = self.blocks_per_group // 8
+		bipg = self.inodes_per_group // 8
+		def window(arr, index, size):
+			return arr[index * size:(index + 1) * size]
+		
+		for bg_index in xrange(len(self.gdt)):
+			sbpos = self.superblock_positions[bg_index]
+			sbblock = (sbpos + 1023) // self.block_size
+			gde = self.gdt[bg_index]
+			
+			self.outf.seek(sbpos)
+			self.write_superblock(bg_index)
+			
+			self.seek_to_block(sbblock+1)
+			self.write_gdt()
+			
+			self.seek_to_block(gde.block_bitmap_block)
+			self.outf.write(window(self.block_allocator.bitmap, bg_index, bbpg))
+			
+			self.seek_to_block(gde.inode_bitmap_block)
+			self.outf.write(window(self.inode_allocator.bitmap, bg_index, bipg))
+	
+	def close(self):
+		"Write all remaining data to the filesystem and close the file"
+		
+		self.write_inode(self.root_inode)
+		self.write_inode(self.lost_plus_found)
+		self.write_all_metadata()
+		self.outf.close()
+
+class Allocator:
+	def __init__(self, base, count):
+		self.count = count
+		self.base = base
+		self.free = count
+		self.nextidx = 0
+		self.bitmap = array.array('B', [0] * (count // 8))
+		self.mark_cb = None
+	
+	def __contains__(self, item):
+		"Check if the item is already used"
+		
+		bitidx = item - self.base
+		return get_bit(self.bitmap[bitidx // 8], bitidx % 8)
+	
+	def alloc(self, **options):
+		"Allocate a new item"
+		
+		while self.nextidx < self.count and (self.base + self.nextidx) in self:
+			self.nextidx += 1
+		if self.nextidx == self.count:
+			raise Exception("No free item available")
+		item = self.base + self.nextidx
+		self.nextidx += 1
+		self.mark_used(item, **options)
+		return item
+	
+	def mark_used(self, item, **options):
+		"Mark the specified item as used"
+		
+		bitidx = item - self.base
+		if item in self:
+			raise Exception("Item already used: " + str(item))
+		self.free -= 1
+		index = bitidx // 8
+		self.bitmap[index] = set_bit(self.bitmap[index], bitidx % 8)
+		if self.mark_cb:
+			self.mark_cb(item, **options)
+	
+	def mark_used_all(self, items, **options):
+		"Mark all specified items as used"
+		
+		for item in items:
+			self.mark_used(item, **options)
+
+class Inode:
+	TYPE_FILE = 1
+	TYPE_DIR = 2
+	TYPE2MODE = {TYPE_FILE: 8, TYPE_DIR: 4}
+	
+	def __init__(self, fs, index, typ):
+		self.fs = fs
+		self.direct = [None] * 12
+		self.indirect = [None] * 3
+		self.pos = 0
+		self.size = 0
+		self.blocks = 0
+		self.index = index
+		self.type = typ
+		self.refcount = 0
+	
+	def as_dirent(self, name):
+		"Return a DirEntry corresponding to this inode"
+		self.refcount += 1
+		return DirEntry(name, self.index, self.type)
+	
+	def new_block(self, data=True):
+		"Get a new block index from allocator and count it here as belonging to the file"
+		
+		block = self.fs.block_allocator.alloc()
+		self.blocks += 1
+		return block
+	
+	def get_or_add_block(self, block):
+		"Get or add a real block to the file"
+		
+		if block < 12:
+			return self.get_or_add_block_direct(block)
+		return self.get_or_add_block_indirect(block)
+	
+	def get_or_add_block_direct(self, block):
+		"Get or add a real block to the file (direct blocks)"
+		
+		if self.direct[block] == None:
+			self.direct[block] = self.new_block()
+		return self.direct[block]
+	
+	def get_or_add_block_indirect(self, block):
+		"Get or add a real block to the file (indirect blocks)"
+		
+		# Determine the indirection level for the desired block
+		level = None
+		for i in range(4):
+			if block < self.fs.indirect_limits[i]:
+				level = i
+				break
+
+		assert level != None
+	
+		# Compute offsets for the topmost level
+		block_offset_in_level = block - self.fs.indirect_limits[level-1];
+		if self.indirect[level-1] == None:
+			self.indirect[level-1] = self.new_block(data = False)
+		current_block = xstruct.create(STRUCT_BLOCK_REFERENCE)
+		current_block.block_id = self.indirect[level-1]
+		offset_in_block = block_offset_in_level // self.fs.indirect_blocks_per_level[level-1]
+	
+		# Navigate through other levels
+		while level > 0:		
+			assert offset_in_block < self.fs.block_ids_per_block
+			
+			level -= 1
+			
+			self.fs.seek_to_block(current_block.block_id, offset_in_block*4)
+			current_block.unpack(self.fs.outf.read(4))
+			
+			if current_block.block_id == 0:
+				# The block does not exist, so alloc one and write it there
+				self.fs.outf.seek(-4, os.SEEK_CUR)
+				current_block.block_id = self.new_block(data=(level==0))
+				self.fs.outf.write(current_block.pack())
+		
+			# If we are on the last level, break here as
+			# there is no next level to visit
+			if level == 0:
+				break
+		
+			# Visit the next level
+			block_offset_in_level %= self.fs.indirect_blocks_per_level[level];
+			offset_in_block = block_offset_in_level // self.fs.indirect_blocks_per_level[level-1]
+
+		return current_block.block_id
+	
+	def do_seek(self):
+		"Perform a seek to the position indicated by self.pos"
+		
+		block = self.pos // self.fs.block_size
+		real_block = self.get_or_add_block(block)
+		offset = self.pos % self.fs.block_size
+		self.fs.seek_to_block(real_block, offset)
+		
+	def write(self, data):
+		"Write a piece of data (arbitrarily long) as the contents of the inode"
+		
+		data_pos = 0		
+		while data_pos < len(data):
+			bytes_remaining_in_block = self.fs.block_size - (self.pos % self.fs.block_size)
+			bytes_to_write = min(bytes_remaining_in_block, len(data)-data_pos)
+			self.do_seek()
+			self.fs.outf.write(data[data_pos:data_pos + bytes_to_write])
+			self.pos += bytes_to_write
+			data_pos += bytes_to_write
+			self.size = max(self.pos, self.size)
+	
+	def align_size_to_block(self):
+		"Align the size of the inode up to block size"
+		
+		self.size = align_up(self.size, self.fs.block_size)
+	
+	def align_pos(self, bytes):
+		"Align the current position up to bytes boundary"
+		
+		self.pos = align_up(self.pos, bytes)
+	
+	def pack(self):
+		"Pack the inode structure and return the result"
+		
+		data = xstruct.create(STRUCT_INODE)
+		data.mode = (Inode.TYPE2MODE[self.type] << 12)
+		data.mode |= 0x1ff # ugo+rwx
+		data.user_id = 0
+		data.size = self.size & 0xFFFFFFFF
+		data.group_id = 0
+		curtime = int(time.time())
+		data.access_time = curtime
+		data.modification_time = curtime
+		data.creation_time = curtime
+		data.deletion_time = 0
+		data.usage_count = self.refcount
+		data.reserved_512_blocks = self.blocks * (self.fs.block_size // 512)
+		data.flags = 0
+		blockconv = lambda x: 0 if x == None else x
+		data.direct_blocks = map(blockconv, self.direct)
+		data.indirect_blocks = map(blockconv, self.indirect)
+		data.version = 0
+		data.file_acl = 0
+		if self.type == Inode.TYPE_FILE:
+			data.size_high = (self.size >> 32)
+		else:
+			# size_high represents dir_acl in this case
+			data.size_high = 0
+		data.mode_high = 0
+		data.user_id_high = 0
+		data.group_id_high = 0
+		return data.pack()
+		
+class DirEntry:
+	"Represents a linked list directory entry"
+	
+	def __init__(self, name, inode, typ):
+		self.name = name.encode('UTF-8')
+		self.inode = inode
+		self.skip = None
+		self.type = typ
+	
+	def size(self):
+		"Return size of the entry in bytes"
+		
+		return align_up(8 + len(self.name)+1, 4)
+	
+	def write(self, inode):
+		"Write the directory entry into the inode"
+		
+		head = xstruct.create(STRUCT_DIR_ENTRY_HEAD)
+		head.inode = self.inode
+		head.skip = self.skip
+		head.name_length = len(self.name)
+		head.inode_type = self.type
+		inode.write(head.pack())
+		inode.write(self.name+'\0')
+		inode.align_pos(4)
+
+class DirWriter:
+	"Manages writing directory entries into an inode (alignment, etc.)"
+	
+	def __init__(self, inode):
+		self.pos = 0
+		self.inode = inode
+		self.prev_entry = None
+		self.prev_pos = None
+	
+	def prev_write(self):
+		"Write a previously remembered entry"
+		
+		if self.prev_entry:
+			self.prev_entry.skip = self.pos - self.prev_pos
+			if self.inode:
+				self.prev_entry.write(self.inode)
+	
+	def add(self, entry):
+		"Add a directory entry to the directory"
+		
+		size = entry.size()
+		block_size = self.inode.fs.block_size
+		if align_up(self.pos, block_size) < align_up(self.pos + size, block_size):
+			self.pos = align_up(self.pos, block_size)
+		self.prev_write()
+		self.prev_entry = entry
+		self.prev_pos = self.pos
+		self.pos += size
+	
+	def finish(self):
+		"Write the last entry and finish writing the directory contents"
+		
+		if not self.inode:
+			return
+		self.pos = align_up(self.pos, self.inode.fs.block_size)
+		self.prev_write()
+		self.inode.align_size_to_block()
+
+def subtree_stats(root, block_size):
+	"Recursively calculate statistics"
+	
+	blocks = 0
+	inodes = 1
+	dir_writer = DirWriter(None)
+	
+	for item in listdir_items(root):
+		inodes += 1
+		if item.is_file:
+			blocks += count_up(item.size, block_size)
+		elif item.is_dir:
+			subtree_blocks, subtree_inodes = subtree_stats(item.path, block_size)
+			blocks += subtree_blocks
+			inodes += subtree_inodes
+	
+	dir_writer.finish()
+	blocks += count_up(dir_writer.pos, block_size)
+	return (blocks, inodes)
+
+def usage(prname):
+	"Print usage syntax"
+	print(prname + " <EXTRA_BYTES> <PATH> <IMAGE>")
+
+def main():
+	if (len(sys.argv) < 4):
+		usage(sys.argv[0])
+		return
+	
+	if (not sys.argv[1].isdigit()):
+		print("<EXTRA_BYTES> must be a number")
+		return
+	
+	extra_bytes = int(sys.argv[1])
+	
+	path = os.path.abspath(sys.argv[2])
+	if (not os.path.isdir(path)):
+		print("<PATH> must be a directory")
+		return
+	
+	block_size = 4096
+	inode_size = 128
+	reserved_inode_count = 10
+	blocks_per_group = 1024
+	inodes_per_group = 512
+	
+	blocks, inodes = subtree_stats(path, block_size)
+	blocks += count_up(extra_bytes, block_size)
+	inodes += reserved_inode_count
+	
+	inodes_per_group = align_up(inodes_per_group, 8)
+	blocks_per_group = align_up(blocks_per_group, 8)
+	
+	inode_table_blocks_per_group = (inodes_per_group * inode_size) // block_size
+	inode_bitmap_blocks_per_group = count_up(inodes_per_group // 8, block_size)
+	block_bitmap_blocks_per_group = count_up(blocks_per_group // 8, block_size)
+	free_blocks_per_group = blocks_per_group
+	free_blocks_per_group -= inode_table_blocks_per_group
+	free_blocks_per_group -= inode_bitmap_blocks_per_group
+	free_blocks_per_group -= block_bitmap_blocks_per_group
+	free_blocks_per_group -= 10 # one for SB and some reserve for GDT
+	
+	block_groups = max(count_up(inodes, inodes_per_group), count_up(blocks, free_blocks_per_group))
+	
+	fs = Filesystem(sys.argv[3], block_groups, blocks_per_group, inodes_per_group,
+	                        block_size, inode_size, reserved_inode_count)
+	
+	fs.subtree_add(fs.root_inode, fs.root_inode, path, is_root=True)
+	fs.close()
+	
+if __name__ == '__main__':
+	main()
Index: tools/mkfat.py
===================================================================
--- tools/mkfat.py	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ tools/mkfat.py	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -37,14 +37,5 @@
 import xstruct
 import array
-
-exclude_names = set(['.svn', '.bzr'])
-
-def align_up(size, alignment):
-	"Return size aligned up to alignment"
-	
-	if (size % alignment == 0):
-		return size
-	
-	return ((size // alignment) + 1) * alignment
+from imgutil import *
 
 def subtree_size(root, cluster_size, dirent_size):
@@ -54,13 +45,10 @@
 	files = 2
 	
-	for name in os.listdir(root):
-		canon = os.path.join(root, name)
-		
-		if (os.path.isfile(canon) and (not name in exclude_names)):
-			size += align_up(os.path.getsize(canon), cluster_size)
+	for item in listdir_items(root):
+		if item.is_file:
+			size += align_up(item.size, cluster_size)
 			files += 1
-		
-		if (os.path.isdir(canon) and (not name in exclude_names)):
-			size += subtree_size(canon, cluster_size, dirent_size)
+		elif item.is_dir:
+			size += subtree_size(item.path, cluster_size, dirent_size)
 			files += 1
 	
@@ -72,14 +60,11 @@
 	return len(os.listdir(root))
 
-def write_file(path, outf, cluster_size, data_start, fat, reserved_clusters):
+def write_file(item, outf, cluster_size, data_start, fat, reserved_clusters):
 	"Store the contents of a file"
 	
-	size = os.path.getsize(path)
 	prev = -1
 	first = 0
 	
-	inf = open(path, "rb")
-	rd = 0;
-	while (rd < size):
+	for data in chunks(item, cluster_size):
 		empty_cluster = fat.index(0)
 		fat[empty_cluster] = 0xffff
@@ -92,11 +77,8 @@
 		prev = empty_cluster
 		
-		data = bytes(inf.read(cluster_size));
 		outf.seek(data_start + (empty_cluster - reserved_clusters) * cluster_size)
 		outf.write(data)
-		rd += len(data)
-	inf.close()
-	
-	return first, size
+	
+	return first, item.size
 
 def write_directory(directory, outf, cluster_size, data_start, fat, reserved_clusters, dirent_size, empty_cluster):
@@ -303,14 +285,11 @@
 		empty_cluster = 0
 	
-	for name in os.listdir(root):
-		canon = os.path.join(root, name)
-		
-		if (os.path.isfile(canon) and (not name in exclude_names)):
-			rv = write_file(canon, outf, cluster_size, data_start, fat, reserved_clusters)
-			directory.append(create_dirent(name, False, rv[0], rv[1]))
-		
-		if (os.path.isdir(canon) and (not name in exclude_names)):
-			rv = recursion(False, canon, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, empty_cluster)
-			directory.append(create_dirent(name, True, rv[0], rv[1]))
+	for item in listdir_items(root):		
+		if item.is_file:
+			rv = write_file(item, outf, cluster_size, data_start, fat, reserved_clusters)
+			directory.append(create_dirent(item.name, False, rv[0], rv[1]))
+		elif item.is_dir:
+			rv = recursion(False, item.path, outf, cluster_size, root_start, data_start, fat, reserved_clusters, dirent_size, empty_cluster)
+			directory.append(create_dirent(item.name, True, rv[0], rv[1]))
 	
 	if (head):
Index: tools/mktmpfs.py
===================================================================
--- tools/mktmpfs.py	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ tools/mktmpfs.py	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -35,6 +35,5 @@
 import os
 import xstruct
-
-exclude_names = set(['.svn', '.bzr'])
+from imgutil import listdir_items, chunks
 
 HEADER = """little:
@@ -71,35 +70,26 @@
 	"Recursive directory walk"
 	
-	for name in os.listdir(root):
-		canon = os.path.join(root, name)
-		
-		if (os.path.isfile(canon) and (not name in exclude_names)):
-			size = os.path.getsize(canon)
-			
-			dentry = xstruct.create(DENTRY_FILE % len(name))
+	for item in listdir_items(root):		
+		if item.is_file:			
+			dentry = xstruct.create(DENTRY_FILE % len(item.name))
 			dentry.kind = TMPFS_FILE
-			dentry.fname_len = len(name)
-			dentry.fname = name.encode('ascii')
-			dentry.flen = size
+			dentry.fname_len = len(item.name)
+			dentry.fname = item.name.encode('ascii')
+			dentry.flen = item.size
 			
 			outf.write(dentry.pack())
 			
-			inf = open(canon, "rb")
-			rd = 0;
-			while (rd < size):
-				data = inf.read(4096);
+			for data in chunks(item, 4096):
 				outf.write(data)
-				rd += len(data)
-			inf.close()
 		
-		if (os.path.isdir(canon) and (not name in exclude_names)):
-			dentry = xstruct.create(DENTRY_DIRECTORY % len(name))
+		elif item.is_dir:
+			dentry = xstruct.create(DENTRY_DIRECTORY % len(item.name))
 			dentry.kind = TMPFS_DIRECTORY
-			dentry.fname_len = len(name)
-			dentry.fname = name.encode('ascii')
+			dentry.fname_len = len(item.name)
+			dentry.fname = item.name.encode('ascii')
 			
 			outf.write(dentry.pack())
 			
-			recursion(canon, outf)
+			recursion(item.path, outf)
 			
 			dentry = xstruct.create(DENTRY_NONE)
Index: tools/xstruct.py
===================================================================
--- tools/xstruct.py	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ tools/xstruct.py	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -1,4 +1,5 @@
 #
 # Copyright (c) 2008 Martin Decky
+# Copyright (c) 2011 Martin Sucha
 # All rights reserved.
 #
@@ -31,4 +32,29 @@
 
 import struct
+import types
+
+ranges = {
+	'B': ((int, long), 0x00, 0xff),
+	'H': ((int, long), 0x0000, 0xffff),
+	'L': ((int, long), 0x00000000, 0xffffffff),
+	'Q': ((int, long), 0x0000000000000000, 0xffffffffffffffff),
+	'b': ((int, long), -0x80, 0x7f),
+	'h': ((int, long), -0x8000, 0x7fff),
+	'l': ((int, long), -0x80000000, 0x7fffffff) ,
+	'q': ((int, long), -0x8000000000000000, 0x7fffffffffffffff),
+}
+
+def check_range(varname, fmt, value):
+	if value == None:
+		raise ValueError('Variable "%s" not set' % varname)
+	if not fmt in ranges:
+		return
+	vartype, varmin, varmax = ranges[fmt]
+	if not isinstance(value, vartype):
+		raise ValueError('Variable "%s" is %s but should be %s' %
+		                 (varname, str(type(value)), str(vartype)))
+	if value < varmin or value > varmax:
+		raise ValueError('Variable "%s" value %s out of range %s..%s' % 
+		                 (varname, repr(value), repr(varmin), repr(varmax)))
 
 class Struct:
@@ -38,12 +64,24 @@
 	def pack(self):
 		args = []
-		for variable in self._args_:
-			if (isinstance(self.__dict__[variable], list)):
-				for item in self.__dict__[variable]:
+		for variable, fmt, length in self._args_:
+			value = self.__dict__[variable]
+			if isinstance(value, list):
+				if length != None and length != len(value):
+					raise ValueError('Variable "%s" length %u does not match %u' %
+				                      (variable, len(value), length))
+				for index, item in enumerate(value):
+					check_range(variable + '[' + repr(index) + ']', fmt, item)
 					args.append(item)
 			else:
-				args.append(self.__dict__[variable])
-		
+				check_range(variable, fmt, value)
+				args.append(value)		
 		return struct.pack(self._format_, *args)
+	
+	def unpack(self, data):
+		values = struct.unpack(self._format_, data)
+		i = 0
+		for variable, fmt, length in self._args_:
+			self.__dict__[variable] = values[i]
+			i += 1
 
 def create(definition):
@@ -77,11 +115,13 @@
 			subtokens = token.split("[")
 			
+			length = None
 			if (len(subtokens) > 1):
-				format += "%d" % int(subtokens[1].split("]")[0])
+				length = int(subtokens[1].split("]")[0])
+				format += "%d" % length
 			
 			format += variable
 			
 			inst.__dict__[subtokens[0]] = None
-			args.append(subtokens[0])
+			args.append((subtokens[0], variable, length))
 			
 			variable = None
Index: uspace/app/bdsh/cmds/modules/cp/cp.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cp/cp.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/app/bdsh/cmds/modules/cp/cp.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -71,6 +71,6 @@
 	size_t blen, int vb)
 {
-	int fd1, fd2, bytes = 0;
-	off64_t total = 0;
+	int fd1, fd2, bytes;
+	off64_t total;
 	int64_t copied = 0;
 	char *buff = NULL;
@@ -104,37 +104,11 @@
 	}
 
-	for (;;) {
-		ssize_t res;
-		size_t written = 0;
-
-		bytes = read(fd1, buff, blen);
-		if (bytes <= 0)
+	while ((bytes = read_all(fd1, buff, blen)) > 0) {
+		if ((bytes = write_all(fd2, buff, bytes)) < 0)
 			break;
 		copied += bytes;
-		res = bytes;
-		do {
-			/*
-			 * Theoretically, it may not be enough to call write()
-			 * only once. Also the previous read() may have
-			 * returned less data than requested.
-			 */
-			bytes = write(fd2, buff + written, res);
-			if (bytes < 0)
-				goto err;
-			written += bytes;
-			res -= bytes;
-		} while (res > 0);
-
-		/* TODO: re-insert assert() once this is stand alone,
-		 * removed as abort() exits the entire shell
-		 */
-		if (res != 0) {
-			printf("\n%zd more bytes than actually exist were copied\n", res);
-			goto err;
-		}
 	}
 
 	if (bytes < 0) {
-err:
 		printf("\nError copying %s, (%d)\n", src, bytes);
 		copied = bytes;
Index: uspace/app/bdsh/cmds/modules/ls/ls.c
===================================================================
--- uspace/app/bdsh/cmds/modules/ls/ls.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/app/bdsh/cmds/modules/ls/ls.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -169,11 +169,11 @@
 		
 		/* fill the name field */
-		tosort[nbdirs].name = (char *) malloc(str_length(dp->d_name) + 1);
+		tosort[nbdirs].name = (char *) malloc(str_size(dp->d_name) + 1);
 		if (!tosort[nbdirs].name) {
 			cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
 			goto out;
 		}
-		
-		str_cpy(tosort[nbdirs].name, str_length(dp->d_name) + 1, dp->d_name);
+
+		str_cpy(tosort[nbdirs].name, str_size(dp->d_name) + 1, dp->d_name);
 		len = snprintf(buff, PATH_MAX - 1, "%s/%s", d, tosort[nbdirs].name);
 		buff[len] = '\0';
Index: uspace/app/bdsh/compl.c
===================================================================
--- uspace/app/bdsh/compl.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/app/bdsh/compl.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -280,4 +280,8 @@
 
 				cs->dir = opendir(*cs->path);
+
+				/* Skip directories that we fail to open. */
+				if (cs->dir == NULL)
+					cs->path++;
 			}
 
Index: uspace/app/bdsh/exec.c
===================================================================
--- uspace/app/bdsh/exec.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/app/bdsh/exec.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -52,5 +52,5 @@
 static int try_access(const char *);
 
-const char *search_dir[] = { "app", "srv", NULL };
+const char *search_dir[] = { "/app", "/srv", NULL };
 
 /* work-around for access() */
Index: uspace/app/bdsh/input.c
===================================================================
--- uspace/app/bdsh/input.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/app/bdsh/input.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -170,5 +170,5 @@
 	}
 	
-	rc = run_command(cmd, usr, &new_iostate);
+	rc = run_command(actual_cmd, usr, &new_iostate);
 	
 finit_with_files:
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/app/init/init.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -294,4 +294,8 @@
 	
 #ifdef CONFIG_MOUNT_DATA
+	/* Make sure fat is running. */
+	if (str_cmp(STRING(RDFMT), "fat") != 0) {
+		srv_start("/srv/fat");
+	}
 	mount_data();
 #else
Index: uspace/app/taskdump/elf_core.c
===================================================================
--- uspace/app/taskdump/elf_core.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/app/taskdump/elf_core.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -38,12 +38,16 @@
  * Looking at core files produced by Linux, these don't have section headers,
  * only program headers, although objdump shows them as having sections.
- * Basically at the beginning there should be a note segment (which we
- * do not write) and one loadable segment per memory area (which we do write).
- *
- * The note segment probably contains register state, etc. -- we don't
- * deal with these yet. Nevertheless you can use these core files with
- * objdump or gdb.
- */
-
+ * Basically at the beginning there should be a note segment followed
+ * by one loadable segment per memory area.
+ *
+ * The note segment contains a series of records with register state,
+ * process info etc. We only write one record NT_PRSTATUS which contains
+ * process/register state (anything which is not register state we fill
+ * with zeroes).
+ */
+
+#include <align.h>
+#include <elf/elf.h>
+#include <elf/elf_linux.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -58,10 +62,10 @@
 #include <udebug.h>
 #include <macros.h>
-
-#include <elf.h>
-#include "include/elf_core.h"
+#include <libarch/istate.h>
+
+#include "elf_core.h"
 
 static off64_t align_foff_up(off64_t, uintptr_t, size_t);
-static int write_all(int, void *, size_t);
+static int align_pos(int, size_t);
 static int write_mem_area(int, as_area_info_t *, async_sess_t *);
 
@@ -83,5 +87,5 @@
  */
 int elf_core_save(const char *file_name, as_area_info_t *ainfo, unsigned int n,
-    async_sess_t *sess)
+    async_sess_t *sess, istate_t *istate)
 {
 	elf_header_t elf_hdr;
@@ -90,12 +94,24 @@
 	elf_word flags;
 	elf_segment_header_t *p_hdr;
+	elf_prstatus_t pr_status;
+	elf_note_t note;
+	size_t word_size;
 
 	int fd;
-	int rc;
+	ssize_t rc;
 	unsigned int i;
 
-	n_ph = n;
-
-	p_hdr = malloc(sizeof(elf_segment_header_t) * n);
+#ifdef __32_BITS__
+	word_size = 4;
+#endif
+#ifdef __64_BITS__
+	word_size = 8;
+#endif
+	memset(&pr_status, 0, sizeof(pr_status));
+	istate_to_elf_regs(istate, &pr_status.regs);
+
+	n_ph = n + 1;
+
+	p_hdr = malloc(sizeof(elf_segment_header_t) * n_ph);
 	if (p_hdr == NULL) {
 		printf("Failed allocating memory.\n");
@@ -115,7 +131,8 @@
 	 * 	ELF header
 	 *	program headers
+	 *	note segment
 	 * repeat:
 	 *	(pad for alignment)
-	 *	segment data
+	 *	core segment
 	 * end repeat
 	 */
@@ -147,30 +164,44 @@
 	foff = elf_hdr.e_phoff + n_ph * sizeof(elf_segment_header_t);
 
-	for (i = 1; i <= n; ++i) {
-		foff = align_foff_up(foff, ainfo[i - 1].start_addr, PAGE_SIZE);
+	memset(&p_hdr[0], 0, sizeof(p_hdr[0]));
+	p_hdr[0].p_type = PT_NOTE;
+	p_hdr[0].p_offset = foff;
+	p_hdr[0].p_vaddr = 0;
+	p_hdr[0].p_paddr = 0;
+	p_hdr[0].p_filesz = sizeof(elf_note_t)
+	    + ALIGN_UP((str_size("CORE") + 1), word_size)
+	    + ALIGN_UP(sizeof(elf_prstatus_t), word_size);
+	p_hdr[0].p_memsz = 0;
+	p_hdr[0].p_flags = 0;
+	p_hdr[0].p_align = 1;
+
+	foff += p_hdr[0].p_filesz;
+
+	for (i = 0; i < n; ++i) {
+		foff = align_foff_up(foff, ainfo[i].start_addr, PAGE_SIZE);
 
 		flags = 0;
-		if (ainfo[i - 1].flags & AS_AREA_READ)
+		if (ainfo[i].flags & AS_AREA_READ)
 			flags |= PF_R;
-		if (ainfo[i - 1].flags & AS_AREA_WRITE)
+		if (ainfo[i].flags & AS_AREA_WRITE)
 			flags |= PF_W;
-		if (ainfo[i - 1].flags & AS_AREA_EXEC)
+		if (ainfo[i].flags & AS_AREA_EXEC)
 			flags |= PF_X;
 
-		memset(&p_hdr[i - 1], 0, sizeof(p_hdr[i - 1]));
-		p_hdr[i - 1].p_type = PT_LOAD;
-		p_hdr[i - 1].p_offset = foff;
-		p_hdr[i - 1].p_vaddr = ainfo[i - 1].start_addr;
-		p_hdr[i - 1].p_paddr = 0;
-		p_hdr[i - 1].p_filesz = ainfo[i - 1].size;
-		p_hdr[i - 1].p_memsz = ainfo[i - 1].size;
-		p_hdr[i - 1].p_flags = flags;
-		p_hdr[i - 1].p_align = PAGE_SIZE;
-
-		foff += ainfo[i - 1].size;
+		memset(&p_hdr[i + 1], 0, sizeof(p_hdr[i + 1]));
+		p_hdr[i + 1].p_type = PT_LOAD;
+		p_hdr[i + 1].p_offset = foff;
+		p_hdr[i + 1].p_vaddr = ainfo[i].start_addr;
+		p_hdr[i + 1].p_paddr = 0;
+		p_hdr[i + 1].p_filesz = ainfo[i].size;
+		p_hdr[i + 1].p_memsz = ainfo[i].size;
+		p_hdr[i + 1].p_flags = flags;
+		p_hdr[i + 1].p_align = PAGE_SIZE;
+
+		foff += ainfo[i].size;
 	}
 
 	rc = write_all(fd, &elf_hdr, sizeof(elf_hdr));
-	if (rc != EOK) {
+	if (rc != sizeof(elf_hdr)) {
 		printf("Failed writing ELF header.\n");
 		free(p_hdr);
@@ -180,5 +211,5 @@
 	for (i = 0; i < n_ph; ++i) {
 		rc = write_all(fd, &p_hdr[i], sizeof(p_hdr[i]));
-		if (rc != EOK) {
+		if (rc != sizeof(p_hdr[i])) {
 			printf("Failed writing program header.\n");
 			free(p_hdr);
@@ -187,5 +218,46 @@
 	}
 
-	for (i = 0; i < n_ph; ++i) {
+	if (lseek(fd, p_hdr[0].p_offset, SEEK_SET) == (off64_t) -1) {
+		printf("Failed writing memory data.\n");
+		free(p_hdr);
+		return EIO;
+	}
+
+	/*
+	 * Write note header
+	 */
+	note.namesz = str_size("CORE") + 1;
+	note.descsz = sizeof(elf_prstatus_t);
+	note.type = NT_PRSTATUS;
+
+	rc = write_all(fd, &note, sizeof(elf_note_t));
+	if (rc != sizeof(elf_note_t)) {
+		printf("Failed writing note header.\n");
+		free(p_hdr);
+		return EIO;
+	}
+
+	rc = write_all(fd, "CORE", note.namesz);
+	if (rc != (ssize_t) note.namesz) {
+		printf("Failed writing note header.\n");
+		free(p_hdr);
+		return EIO;
+	}
+
+	rc = align_pos(fd, word_size);
+	if (rc != EOK) {
+		printf("Failed writing note header.\n");
+		free(p_hdr);
+		return EIO;
+	}
+
+	rc = write_all(fd, &pr_status, sizeof(elf_prstatus_t));
+	if (rc != sizeof(elf_prstatus_t)) {
+		printf("Failed writing register data.\n");
+		free(p_hdr);
+		return EIO;
+	}
+
+	for (i = 1; i < n_ph; ++i) {
 		if (lseek(fd, p_hdr[i].p_offset, SEEK_SET) == (off64_t) -1) {
 			printf("Failed writing memory data.\n");
@@ -193,5 +265,5 @@
 			return EIO;
 		}
-		if (write_mem_area(fd, &ainfo[i], sess) != EOK) {
+		if (write_mem_area(fd, &ainfo[i - 1], sess) != EOK) {
 			printf("Failed writing memory data.\n");
 			free(p_hdr);
@@ -210,8 +282,8 @@
 	off64_t rva = vaddr % page_size;
 	off64_t rfo = foff % page_size;
-	
+
 	if (rva >= rfo)
 		return (foff + (rva - rfo));
-	
+
 	return (foff + (page_size + (rva - rfo)));
 }
@@ -231,5 +303,5 @@
 	size_t total;
 	uintptr_t addr;
-	int rc;
+	ssize_t rc;
 
 	addr = area->start_addr;
@@ -245,5 +317,5 @@
 
 		rc = write_all(fd, buffer, to_copy);
-		if (rc != EOK) {
+		if (rc != (ssize_t) to_copy) {
 			printf("Failed writing memory contents.\n");
 			return EIO;
@@ -257,35 +329,23 @@
 }
 
-/** Write until the buffer is written in its entirety.
- *
- * This function fails if it cannot write exactly @a len bytes to the file.
- *
- * @param fd		The file to write to.
- * @param buf		Data, @a len bytes long.
- * @param len		Number of bytes to write.
- *
- * @return		EOK on error, return value from write() if writing
- *			failed.
- */
-static int write_all(int fd, void *data, size_t len)
+static int align_pos(int fd, size_t align)
 {
-	int cnt = 0;
-
-	do {
-		data += cnt;
-		len -= cnt;
-		cnt = write(fd, data, len);
-	} while (cnt > 0 && (len - cnt) > 0);
-
-	if (cnt < 0)
-		return cnt;
-
-	if (len - cnt > 0)
-		return EIO;
+	off64_t cur_pos;
+	size_t rem, adv;
+
+	cur_pos = lseek(fd, 0, SEEK_CUR);
+	if (cur_pos < 0)
+		return -1;
+
+	rem = cur_pos % align;
+	adv = align - rem;
+
+	cur_pos = lseek(fd, adv, SEEK_CUR);
+	if (cur_pos < 0)
+		return -1;
 
 	return EOK;
 }
 
-
 /** @}
  */
Index: pace/app/taskdump/include/elf.h
===================================================================
--- uspace/app/taskdump/include/elf.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ 	(revision )
@@ -1,349 +1,0 @@
-/*
- * Copyright (c) 2006 Sergey Bondari
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - 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.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-/** @addtogroup generic	
- * @{
- */
-/** @file
- */
-
-#ifndef ELF_H_
-#define ELF_H_
-
-#include <arch/elf.h>
-#include <sys/types.h>
-
-/**
- * current ELF version
- */
-#define	EV_CURRENT	1
-
-/** 
- * ELF types 
- */
-#define ET_NONE		0	/* No type */
-#define ET_REL		1	/* Relocatable file */
-#define ET_EXEC		2	/* Executable */
-#define ET_DYN		3	/* Shared object */
-#define ET_CORE		4	/* Core */
-#define ET_LOPROC	0xff00	/* Processor specific */
-#define ET_HIPROC	0xffff	/* Processor specific */
-
-/** 
- * ELF machine types
- */
-#define EM_NO		0	/* No machine */
-#define EM_SPARC	2	/* SPARC */
-#define EM_386		3	/* i386 */
-#define EM_MIPS		8	/* MIPS RS3000 */
-#define EM_MIPS_RS3_LE	10	/* MIPS RS3000 LE */
-#define EM_PPC		20	/* PPC32 */
-#define EM_PPC64	21	/* PPC64 */
-#define EM_ARM		40	/* ARM */
-#define EM_SPARCV9	43	/* SPARC64 */
-#define EM_IA_64	50	/* IA-64 */
-#define EM_X86_64	62	/* AMD64/EMT64 */
-
-/**
- * ELF identification indexes
- */
-#define EI_MAG0		0
-#define EI_MAG1		1
-#define EI_MAG2		2
-#define EI_MAG3		3
-#define EI_CLASS	4		/* File class */
-#define EI_DATA		5		/* Data encoding */
-#define EI_VERSION	6		/* File version */
-#define EI_OSABI	7
-#define EI_ABIVERSION	8
-#define EI_PAD		9		/* Start of padding bytes */
-#define EI_NIDENT	16		/* ELF identification table size */
-
-/**
- * ELF magic number
- */
-#define ELFMAG0		0x7f
-#define ELFMAG1		'E'
-#define ELFMAG2		'L'
-#define ELFMAG3		'F'
-
-/**
- * ELF file classes
- */
-#define ELFCLASSNONE	0
-#define ELFCLASS32	1
-#define ELFCLASS64	2
-
-/**
- * ELF data encoding types
- */
-#define ELFDATANONE	0
-#define ELFDATA2LSB	1		/* Least significant byte first (little endian) */
-#define ELFDATA2MSB	2		/* Most signigicant byte first (big endian) */
-
-/**
- * ELF error return codes
- */
-#define EE_OK			0	/* No error */
-#define EE_INVALID		1	/* Invalid ELF image */
-#define	EE_MEMORY		2	/* Cannot allocate address space */
-#define EE_INCOMPATIBLE		3	/* ELF image is not compatible with current architecture */
-#define EE_UNSUPPORTED		4	/* Non-supported ELF (e.g. dynamic ELFs) */
-#define EE_IRRECOVERABLE	5
-
-/**
- * ELF section types
- */
-#define SHT_NULL		0
-#define SHT_PROGBITS		1
-#define SHT_SYMTAB		2
-#define SHT_STRTAB		3
-#define SHT_RELA		4
-#define SHT_HASH		5
-#define SHT_DYNAMIC		6
-#define SHT_NOTE		7
-#define SHT_NOBITS		8
-#define SHT_REL			9
-#define SHT_SHLIB		10
-#define SHT_DYNSYM		11
-#define SHT_LOOS		0x60000000
-#define SHT_HIOS		0x6fffffff
-#define SHT_LOPROC		0x70000000
-#define SHT_HIPROC		0x7fffffff
-#define SHT_LOUSER		0x80000000
-#define SHT_HIUSER		0xffffffff
-
-/**
- * ELF section flags
- */
-#define SHF_WRITE		0x1 
-#define SHF_ALLOC		0x2
-#define SHF_EXECINSTR		0x4
-#define SHF_TLS			0x400
-#define SHF_MASKPROC		0xf0000000
-
-/** Macros for decomposing elf_symbol.st_info into binging and type */
-#define ELF_ST_BIND(i)		((i) >> 4)
-#define ELF_ST_TYPE(i)		((i) & 0x0f)
-#define ELF_ST_INFO(b, t)	(((b) << 4) + ((t) & 0x0f))
-
-/**
- * Symbol binding
- */
-#define STB_LOCAL		0
-#define STB_GLOBAL		1
-#define STB_WEAK		2
-#define STB_LOPROC		13
-#define STB_HIPROC		15
-
-/**
- * Symbol types
- */
-#define STT_NOTYPE		0
-#define STT_OBJECT		1
-#define STT_FUNC		2
-#define STT_SECTION		3
-#define STT_FILE		4
-#define STT_LOPROC		13
-#define STT_HIPROC		15
-
-/**
- * Program segment types
- */
-#define PT_NULL			0
-#define PT_LOAD			1
-#define PT_DYNAMIC		2
-#define PT_INTERP		3
-#define PT_NOTE			4
-#define PT_SHLIB		5
-#define PT_PHDR			6
-#define PT_LOPROC		0x70000000
-#define PT_HIPROC		0x7fffffff
-
-/**
- * Program segment attributes.
- */
-#define PF_X	1
-#define PF_W	2
-#define PF_R	4
-
-/**
- * ELF data types
- *
- * These types are found to be identical in both 32-bit and 64-bit
- * ELF object file specifications. They are the only types used
- * in ELF header.
- */
-typedef uint64_t elf_xword;
-typedef int64_t elf_sxword;
-typedef uint32_t elf_word;
-typedef int32_t elf_sword;
-typedef uint16_t elf_half;
-
-/**
- * 32-bit ELF data types.
- *
- * These types are specific for 32-bit format.
- */
-typedef uint32_t elf32_addr;
-typedef uint32_t elf32_off;
-
-/**
- * 64-bit ELF data types.
- *
- * These types are specific for 64-bit format.
- */
-typedef uint64_t elf64_addr;
-typedef uint64_t elf64_off;
-
-/** ELF header */
-struct elf32_header {
-	uint8_t e_ident[EI_NIDENT];
-	elf_half e_type;
-	elf_half e_machine;
-	elf_word e_version;
-	elf32_addr e_entry;
-	elf32_off e_phoff;
-	elf32_off e_shoff;
-	elf_word e_flags;
-	elf_half e_ehsize;
-	elf_half e_phentsize;
-	elf_half e_phnum;
-	elf_half e_shentsize;
-	elf_half e_shnum;
-	elf_half e_shstrndx;
-};
-struct elf64_header {
-	uint8_t e_ident[EI_NIDENT];
-	elf_half e_type;
-	elf_half e_machine;
-	elf_word e_version;
-	elf64_addr e_entry;
-	elf64_off e_phoff;
-	elf64_off e_shoff;
-	elf_word e_flags;
-	elf_half e_ehsize;
-	elf_half e_phentsize;
-	elf_half e_phnum;
-	elf_half e_shentsize;
-	elf_half e_shnum;
-	elf_half e_shstrndx;
-};
-
-/*
- * ELF segment header.
- * Segments headers are also known as program headers.
- */
-struct elf32_segment_header {
-	elf_word p_type;
-	elf32_off p_offset;
-	elf32_addr p_vaddr;
-	elf32_addr p_paddr;
-	elf_word p_filesz;
-	elf_word p_memsz;
-	elf_word p_flags;
-	elf_word p_align;
-};
-struct elf64_segment_header {
-	elf_word p_type;
-	elf_word p_flags;
-	elf64_off p_offset;
-	elf64_addr p_vaddr;
-	elf64_addr p_paddr;
-	elf_xword p_filesz;
-	elf_xword p_memsz;
-	elf_xword p_align;
-};
-
-/*
- * ELF section header
- */
-struct elf32_section_header {
-	elf_word sh_name;
-	elf_word sh_type;
-	elf_word sh_flags;
-	elf32_addr sh_addr;
-	elf32_off sh_offset;
-	elf_word sh_size;
-	elf_word sh_link;
-	elf_word sh_info;
-	elf_word sh_addralign;
-	elf_word sh_entsize;
-};
-struct elf64_section_header {
-	elf_word sh_name;
-	elf_word sh_type;
-	elf_xword sh_flags;
-	elf64_addr sh_addr;
-	elf64_off sh_offset;
-	elf_xword sh_size;
-	elf_word sh_link;
-	elf_word sh_info;
-	elf_xword sh_addralign;
-	elf_xword sh_entsize;
-};
-
-/*
- * ELF symbol table entry
- */
-struct elf32_symbol {
-	elf_word st_name;
-	elf32_addr st_value;
-	elf_word st_size;
-	uint8_t st_info;
-	uint8_t st_other;
-	elf_half st_shndx;
-};
-struct elf64_symbol {
-	elf_word st_name;
-	uint8_t st_info;
-	uint8_t st_other;
-	elf_half st_shndx;
-	elf64_addr st_value;
-	elf_xword st_size;
-};
-
-#ifdef __32_BITS__ 
-typedef struct elf32_header elf_header_t;
-typedef struct elf32_segment_header elf_segment_header_t;
-typedef struct elf32_section_header elf_section_header_t;
-typedef struct elf32_symbol elf_symbol_t;
-#endif
-#ifdef __64_BITS__
-typedef struct elf64_header elf_header_t;
-typedef struct elf64_segment_header elf_segment_header_t;
-typedef struct elf64_section_header elf_section_header_t;
-typedef struct elf64_symbol elf_symbol_t;
-#endif
-
-extern char *elf_error(unsigned int rc);
-
-#endif
-
-/** @}
- */
Index: uspace/app/taskdump/include/elf_core.h
===================================================================
--- uspace/app/taskdump/include/elf_core.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/app/taskdump/include/elf_core.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -37,7 +37,9 @@
 
 #include <async.h>
+#include <elf/elf_linux.h>
+#include <libarch/istate.h>
 
 extern int elf_core_save(const char *, as_area_info_t *, unsigned int,
-    async_sess_t *);
+    async_sess_t *, istate_t *);
 
 #endif
Index: uspace/app/taskdump/include/symtab.h
===================================================================
--- uspace/app/taskdump/include/symtab.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/app/taskdump/include/symtab.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -36,6 +36,6 @@
 #define SYMTAB_H_
 
+#include <elf/elf.h>
 #include <sys/types.h>
-#include <elf.h>
 
 typedef struct {
Index: uspace/app/taskdump/symtab.c
===================================================================
--- uspace/app/taskdump/symtab.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/app/taskdump/symtab.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -36,4 +36,5 @@
  */
 
+#include <elf/elf.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -43,5 +44,4 @@
 #include <fcntl.h>
 
-#include <elf.h>
 #include "include/symtab.h"
 
@@ -50,5 +50,4 @@
     elf_section_header_t *shdr);
 static int chunk_load(int fd, off64_t start, size_t size, void **ptr);
-static int read_all(int fd, void *buf, size_t len);
 
 /** Load symbol table from an ELF file.
@@ -90,5 +89,5 @@
 
 	rc = read_all(fd, &elf_hdr, sizeof(elf_header_t));
-	if (rc != EOK) {
+	if (rc != sizeof(elf_header_t)) {
 		printf("failed reading elf header\n");
 		free(stab);
@@ -312,5 +311,5 @@
 
 	rc = read_all(fd, sec_hdr, sizeof(elf_section_header_t));
-	if (rc != EOK)
+	if (rc != sizeof(elf_section_header_t))
 		return EIO;
 
@@ -331,8 +330,9 @@
 static int chunk_load(int fd, off64_t start, size_t size, void **ptr)
 {
-	int rc;
-
-	rc = lseek(fd, start, SEEK_SET);
-	if (rc == (off64_t) -1) {
+	ssize_t rc;
+	off64_t offs;
+
+	offs = lseek(fd, start, SEEK_SET);
+	if (offs == (off64_t) -1) {
 		printf("failed seeking chunk\n");
 		*ptr = NULL;
@@ -347,5 +347,5 @@
 
 	rc = read_all(fd, *ptr, size);
-	if (rc != EOK) {
+	if (rc != (ssize_t) size) {
 		printf("failed reading chunk\n");
 		free(*ptr);
@@ -357,34 +357,4 @@
 }
 
-/** Read until the buffer is read in its entirety.
- *
- * This function fails if it cannot read exactly @a len bytes from the file.
- *
- * @param fd		The file to read from.
- * @param buf		Buffer for storing data, @a len bytes long.
- * @param len		Number of bytes to read.
- *
- * @return		EOK on error, EIO if file is short or return value
- *			from read() if reading failed.
- */
-static int read_all(int fd, void *buf, size_t len)
-{
-	int cnt = 0;
-
-	do {
-		buf += cnt;
-		len -= cnt;
-		cnt = read(fd, buf, len);
-	} while (cnt > 0 && (len - cnt) > 0);
-
-	if (cnt < 0)
-		return cnt;
-
-	if (len - cnt > 0)
-		return EIO;
-
-	return EOK;
-}
-
 /** @}
  */
Index: uspace/app/taskdump/taskdump.c
===================================================================
--- uspace/app/taskdump/taskdump.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/app/taskdump/taskdump.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -34,4 +34,5 @@
 
 #include <async.h>
+#include <elf/elf_linux.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -72,4 +73,6 @@
 static char *get_app_task_name(void);
 static char *fmt_sym_address(uintptr_t addr);
+
+static istate_t reg_state;
 
 int main(int argc, char *argv[])
@@ -293,5 +296,8 @@
 	if (write_core_file) {
 		printf("Writing core file '%s'\n", core_file_name);
-		rc = elf_core_save(core_file_name, ainfo_buf, n_areas, sess);
+
+		rc = elf_core_save(core_file_name, ainfo_buf, n_areas, sess,
+		    &reg_state);
+
 		if (rc != EOK) {
 			printf("Failed writing core file.\n");
@@ -321,4 +327,7 @@
 	pc = istate_get_pc(&istate);
 	fp = istate_get_fp(&istate);
+
+	/* Save register state for dumping to core file later. */
+	reg_state = istate;
 
 	sym_pc = fmt_sym_address(pc);
Index: uspace/drv/bus/usb/usbmast/bo_trans.c
===================================================================
--- uspace/drv/bus/usb/usbmast/bo_trans.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/drv/bus/usb/usbmast/bo_trans.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -58,36 +58,46 @@
  * @param tag		Command block wrapper tag (automatically compared
  *			with answer)
- * @param cmd		Command block
- * @param cmd_size	Command block size in bytes
- * @param ddir		Direction in which data will be transferred
- * @param dbuf		Data send/receive buffer
- * @param dbuf_size	Size of the data buffer
- * @param xferred_size	Number of bytes actually transferred
+ * @param cmd		SCSI command
  *
  * @return		Error code
  */
-static int usb_massstor_cmd(usbmast_fun_t *mfun, uint32_t tag, const void *cmd,
-    size_t cmd_size, usb_direction_t ddir, void *dbuf, size_t dbuf_size,
-    size_t *xferred_size)
+int usb_massstor_cmd(usbmast_fun_t *mfun, uint32_t tag, scsi_cmd_t *cmd)
 {
 	int rc;
+	int retval = EOK;
 	size_t act_size;
 	usb_pipe_t *bulk_in_pipe = mfun->mdev->usb_dev->pipes[BULK_IN_EP].pipe;
 	usb_pipe_t *bulk_out_pipe = mfun->mdev->usb_dev->pipes[BULK_OUT_EP].pipe;
+	usb_direction_t ddir;
+	void *dbuf;
+	size_t dbuf_size;
+
+	if (cmd->data_out != NULL && cmd->data_in == NULL) {
+		ddir = USB_DIRECTION_OUT;
+		dbuf = (void *)cmd->data_out;
+		dbuf_size = cmd->data_out_size;
+	} else if (cmd->data_out == NULL && cmd->data_in != NULL) {
+		ddir = USB_DIRECTION_IN;
+		dbuf = cmd->data_in;
+		dbuf_size = cmd->data_in_size;
+	} else {
+		assert(false);
+	}
 
 	/* Prepare CBW - command block wrapper */
 	usb_massstor_cbw_t cbw;
 	usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, mfun->lun,
-	    cmd_size, cmd);
+	    cmd->cdb_size, cmd->cdb);
 
 	/* Send the CBW. */
+	MASTLOG("Sending CBW.\n");
 	rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
 	MASTLOG("CBW '%s' sent: %s.\n",
 	    usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
 	    str_error(rc));
-	if (rc != EOK) {
-		return rc;
-	}
-
+	if (rc != EOK)
+		return EIO;
+
+	MASTLOG("Transferring data.\n");
 	if (ddir == USB_DIRECTION_IN) {
 		/* Recieve data from the device. */
@@ -104,10 +114,15 @@
 	}
 
-	if (rc != EOK) {
-		/*
-		 * XXX If the pipe is stalled, we should clear it
-		 * and read CSW.
-		 */
-		return rc;
+	if (rc == ESTALL) {
+		/* Clear stall condition and continue below to read CSW. */
+		if (ddir == USB_DIRECTION_IN) {
+			usb_pipe_clear_halt(&mfun->mdev->usb_dev->ctrl_pipe,
+			    mfun->mdev->usb_dev->pipes[BULK_IN_EP].pipe);
+		} else {
+			usb_pipe_clear_halt(&mfun->mdev->usb_dev->ctrl_pipe,
+			    mfun->mdev->usb_dev->pipes[BULK_OUT_EP].pipe);
+		}
+        } else if (rc != EOK) {
+		return EIO;
 	}
 
@@ -115,4 +130,5 @@
 	usb_massstor_csw_t csw;
 	size_t csw_size;
+	MASTLOG("Reading CSW.\n");
 	rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
 	MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
@@ -121,15 +137,15 @@
 	if (rc != EOK) {
 		MASTLOG("rc != EOK\n");
-		return rc;
+		return EIO;
 	}
 
 	if (csw_size != sizeof(csw)) {
 		MASTLOG("csw_size != sizeof(csw)\n");
-		return ERANGE;
+		return EIO;
 	}
 
 	if (csw.dCSWTag != tag) {
 		MASTLOG("csw.dCSWTag != tag\n");
-		return EBADCHECKSUM;
+		return EIO;
 	}
 
@@ -137,9 +153,19 @@
 	 * Determine the actual return value from the CSW.
 	 */
-	if (csw.dCSWStatus != 0) {
-		MASTLOG("csw.dCSWStatus != 0\n");
-		// FIXME: better error code
-		// FIXME: distinguish 0x01 and 0x02
-		return EXDEV;
+	switch (csw.dCSWStatus) {
+	case cbs_passed:
+		cmd->status = CMDS_GOOD;
+		break;
+	case cbs_failed:
+		MASTLOG("Command failed\n");
+		cmd->status = CMDS_FAILED;
+		break;
+	case cbs_phase_error:
+		MASTLOG("Phase error\n");
+		retval = EIO;
+		break;
+	default:
+		retval = EIO;
+		break;
 	}
 
@@ -147,5 +173,5 @@
 	if (residue > dbuf_size) {
 		MASTLOG("residue > dbuf_size\n");
-		return ERANGE;
+		return EIO;
 	}
 
@@ -158,48 +184,8 @@
 	 */
 
-	if (xferred_size != NULL)
-		*xferred_size = dbuf_size - residue;
-
-	return EOK;
-}
-
-/** Perform data-in command.
- *
- * @param mfun		Mass storage function
- * @param tag		Command block wrapper tag (automatically compared with
- *			answer)
- * @param cmd		CDB (Command Descriptor)
- * @param cmd_size	CDB length in bytes
- * @param dbuf		Data receive buffer
- * @param dbuf_size	Data receive buffer size in bytes
- * @param proc_size	Number of bytes actually processed by device
- *
- * @return Error code
- */
-int usb_massstor_data_in(usbmast_fun_t *mfun, uint32_t tag, const void *cmd,
-    size_t cmd_size, void *dbuf, size_t dbuf_size, size_t *proc_size)
-{
-	return usb_massstor_cmd(mfun, tag, cmd, cmd_size, USB_DIRECTION_IN,
-	    dbuf, dbuf_size, proc_size);
-}
-
-/** Perform data-out command.
- *
- * @param mfun		Mass storage function
- * @param tag		Command block wrapper tag (automatically compared with
- *			answer)
- * @param cmd		CDB (Command Descriptor)
- * @param cmd_size	CDB length in bytes
- * @param data		Command data
- * @param data_size	Size of @a data in bytes
- * @param proc_size	Number of bytes actually processed by device
- *
- * @return Error code
- */
-int usb_massstor_data_out(usbmast_fun_t *mfun, uint32_t tag, const void *cmd,
-    size_t cmd_size, const void *data, size_t data_size, size_t *proc_size)
-{
-	return usb_massstor_cmd(mfun, tag, cmd, cmd_size, USB_DIRECTION_OUT,
-	    (void *) data, data_size, proc_size);
+	if (ddir == USB_DIRECTION_IN)
+		cmd->rcvd_size = dbuf_size - residue;
+
+	return retval;
 }
 
Index: uspace/drv/bus/usb/usbmast/bo_trans.h
===================================================================
--- uspace/drv/bus/usb/usbmast/bo_trans.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/drv/bus/usb/usbmast/bo_trans.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -47,8 +47,46 @@
 #define BULK_OUT_EP 1
 
-extern int usb_massstor_data_in(usbmast_fun_t *, uint32_t, const void *,
-    size_t, void *, size_t, size_t *);
-extern int usb_massstor_data_out(usbmast_fun_t *, uint32_t, const void *,
-    size_t, const void *, size_t, size_t *);
+typedef enum cmd_status {
+	CMDS_GOOD,
+	CMDS_FAILED
+} cmd_status_t;
+
+/** SCSI command.
+ *
+ * Contains (a subset of) the input and output arguments of SCSI
+ * Execute Command procedure call (see SAM-4 chapter 5.1)
+ */
+typedef struct {
+	/*
+	 * Related to IN fields
+	 */
+
+	/** Command Descriptor Block */
+	void *cdb;
+	/** CDB size in bytes */
+	size_t cdb_size;
+
+	/** Outgoing data */
+	const void *data_out;
+	/** Size of outgoing data in bytes */
+	size_t data_out_size;
+
+	/*
+	 * Related to OUT fields
+	 */
+
+	/** Buffer for incoming data */
+	void *data_in;
+	/** Size of input buffer in bytes */
+	size_t data_in_size;
+
+	/** Number of bytes actually received */
+	size_t rcvd_size;
+
+	/** Status */
+	cmd_status_t status;
+} scsi_cmd_t;
+
+extern int usb_massstor_cmd(usbmast_fun_t *, uint32_t, scsi_cmd_t *);
 extern int usb_massstor_reset(usbmast_dev_t *);
 extern void usb_massstor_reset_recovery(usbmast_dev_t *);
Index: uspace/drv/bus/usb/usbmast/cmdw.h
===================================================================
--- uspace/drv/bus/usb/usbmast/cmdw.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/drv/bus/usb/usbmast/cmdw.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -57,4 +57,10 @@
 } __attribute__((packed)) usb_massstor_csw_t;
 
+enum cmd_block_status {
+	cbs_passed	= 0x00,
+	cbs_failed	= 0x01,
+	cbs_phase_error = 0x02
+};
+
 extern void usb_massstor_cbw_prepare(usb_massstor_cbw_t *, uint32_t, uint32_t,
     usb_direction_t, uint8_t, uint8_t, const uint8_t *);
Index: uspace/drv/bus/usb/usbmast/scsi_ms.c
===================================================================
--- uspace/drv/bus/usb/usbmast/scsi_ms.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/drv/bus/usb/usbmast/scsi_ms.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -61,4 +61,63 @@
 }
 
+static void usbmast_dump_sense(scsi_sense_data_t *sense_buf)
+{
+	unsigned sense_key;
+
+	sense_key = sense_buf->flags_key & 0x0f;
+	printf("Got sense data. Sense key: 0x%x (%s), ASC 0x%02x, "
+	    "ASCQ 0x%02x.\n", sense_key,
+	    scsi_get_sense_key_str(sense_key),
+	    sense_buf->additional_code,
+	    sense_buf->additional_cqual);
+}
+
+/** Run SCSI command.
+ *
+ * Run command and repeat in case of unit attention.
+ * XXX This is too simplified.
+ */
+static int usbmast_run_cmd(usbmast_fun_t *mfun, scsi_cmd_t *cmd)
+{
+	uint8_t sense_key;
+	scsi_sense_data_t sense_buf;
+	int rc;
+
+	do {
+		rc = usb_massstor_cmd(mfun, 0xDEADBEEF, cmd);
+		if (rc != EOK) {
+			usb_log_error("Inquiry transport failed, device %s: %s.\n",
+			   mfun->mdev->ddf_dev->name, str_error(rc));
+			return rc;
+		}
+
+		if (cmd->status == CMDS_GOOD)
+			return EOK;
+
+		usb_log_error("SCSI command failed, device %s.\n",
+		    mfun->mdev->ddf_dev->name);
+
+		rc = usbmast_request_sense(mfun, &sense_buf, sizeof(sense_buf));
+		if (rc != EOK) {
+			usb_log_error("Failed to read sense data.\n");
+			return EIO;
+		}
+
+		/* Dump sense data to log */
+		usbmast_dump_sense(&sense_buf);
+
+		/* Get sense key */
+		sense_key = sense_buf.flags_key & 0x0f;
+
+		if (sense_key == SCSI_SK_UNIT_ATTENTION) {
+			printf("Got unit attention. Re-trying command.\n");
+		}
+
+	} while (sense_key == SCSI_SK_UNIT_ATTENTION);
+
+	/* Command status is not good, nevertheless transport succeeded. */
+	return EOK;
+}
+
 /** Perform SCSI Inquiry command on USB mass storage device.
  *
@@ -70,5 +129,5 @@
 {
 	scsi_std_inquiry_data_t inq_data;
-	size_t response_len;
+	scsi_cmd_t cmd;
 	scsi_cdb_inquiry_t cdb;
 	int rc;
@@ -78,16 +137,27 @@
 	cdb.alloc_len = host2uint16_t_be(sizeof(inq_data));
 
-	rc = usb_massstor_data_in(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
-	    sizeof(cdb), &inq_data, sizeof(inq_data), &response_len);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_in = &inq_data;
+	cmd.data_in_size = sizeof(inq_data);
+
+	rc = usb_massstor_cmd(mfun, 0xDEADBEEF, &cmd);
 
 	if (rc != EOK) {
-		usb_log_error("Inquiry failed, device %s: %s.\n",
-		   mfun->mdev->ddf_dev->name, str_error(rc));
-		return rc;
-	}
-
-	if (response_len < SCSI_STD_INQUIRY_DATA_MIN_SIZE) {
+		usb_log_error("Inquiry transport failed, device %s: %s.\n",
+		   mfun->mdev->ddf_dev->name, str_error(rc));
+		return rc;
+	}
+
+	if (cmd.status != CMDS_GOOD) {
+		usb_log_error("Inquiry command failed, device %s.\n",
+		   mfun->mdev->ddf_dev->name);
+		return EIO;
+	}
+
+	if (cmd.rcvd_size < SCSI_STD_INQUIRY_DATA_MIN_SIZE) {
 		usb_log_error("SCSI Inquiry response too short (%zu).\n",
-		    response_len);
+		    cmd.rcvd_size);
 		return EIO;
 	}
@@ -127,6 +197,6 @@
 int usbmast_request_sense(usbmast_fun_t *mfun, void *buf, size_t size)
 {
+	scsi_cmd_t cmd;
 	scsi_cdb_request_sense_t cdb;
-	size_t data_len;
 	int rc;
 
@@ -135,8 +205,13 @@
 	cdb.alloc_len = min(size, SCSI_SENSE_DATA_MAX_SIZE);
 
-	rc = usb_massstor_data_in(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
-	    sizeof(cdb), buf, size, &data_len);
-
-        if (rc != EOK) {
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_in = buf;
+	cmd.data_in_size = size;
+
+	rc = usb_massstor_cmd(mfun, 0xDEADBEEF, &cmd);
+
+        if (rc != EOK || cmd.status != CMDS_GOOD) {
 		usb_log_error("Request Sense failed, device %s: %s.\n",
 		   mfun->mdev->ddf_dev->name, str_error(rc));
@@ -144,8 +219,8 @@
 	}
 
-	if (data_len < SCSI_SENSE_DATA_MIN_SIZE) {
+	if (cmd.rcvd_size < SCSI_SENSE_DATA_MIN_SIZE) {
 		/* The missing bytes should be considered to be zeroes. */
-		memset((uint8_t *)buf + data_len, 0,
-		    SCSI_SENSE_DATA_MIN_SIZE - data_len);
+		memset((uint8_t *)buf + cmd.rcvd_size, 0,
+		    SCSI_SENSE_DATA_MIN_SIZE - cmd.rcvd_size);
 	}
 
@@ -164,7 +239,7 @@
     uint32_t *block_size)
 {
+	scsi_cmd_t cmd;
 	scsi_cdb_read_capacity_10_t cdb;
 	scsi_read_capacity_10_data_t data;
-	size_t data_len;
 	int rc;
 
@@ -172,16 +247,27 @@
 	cdb.op_code = SCSI_CMD_READ_CAPACITY_10;
 
-	rc = usb_massstor_data_in(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
-	    sizeof(cdb), &data, sizeof(data), &data_len);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_in = &data;
+	cmd.data_in_size = sizeof(data);
+
+	rc = usbmast_run_cmd(mfun, &cmd);
 
         if (rc != EOK) {
-		usb_log_error("Read Capacity (10) failed, device %s: %s.\n",
-		   mfun->mdev->ddf_dev->name, str_error(rc));
-		return rc;
-	}
-
-	if (data_len < sizeof(data)) {
+		usb_log_error("Read Capacity (10) transport failed, device %s: %s.\n",
+		   mfun->mdev->ddf_dev->name, str_error(rc));
+		return rc;
+	}
+
+	if (cmd.status != CMDS_GOOD) {
+		usb_log_error("Read Capacity (10) command failed, device %s.\n",
+		   mfun->mdev->ddf_dev->name);
+		return EIO;
+	}
+
+	if (cmd.rcvd_size < sizeof(data)) {
 		usb_log_error("SCSI Read Capacity response too short (%zu).\n",
-		    data_len);
+		    cmd.rcvd_size);
 		return EIO;
 	}
@@ -203,33 +289,42 @@
 int usbmast_read(usbmast_fun_t *mfun, uint64_t ba, size_t nblocks, void *buf)
 {
-	scsi_cdb_read_12_t cdb;
-	size_t data_len;
-	int rc;
-
-	/* XXX Need softstate to store block size. */
+	scsi_cmd_t cmd;
+	scsi_cdb_read_10_t cdb;
+	int rc;
 
 	if (ba > UINT32_MAX)
 		return ELIMIT;
 
-	if ((uint64_t)nblocks * mfun->block_size > UINT32_MAX)
+	if (nblocks > UINT16_MAX)
 		return ELIMIT;
 
 	memset(&cdb, 0, sizeof(cdb));
-	cdb.op_code = SCSI_CMD_READ_12;
+	cdb.op_code = SCSI_CMD_READ_10;
 	cdb.lba = host2uint32_t_be(ba);
-	cdb.xfer_len = host2uint32_t_be(nblocks);
-
-	rc = usb_massstor_data_in(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
-	    sizeof(cdb), buf, nblocks * mfun->block_size, &data_len);
+	cdb.xfer_len = host2uint16_t_be(nblocks);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_in = buf;
+	cmd.data_in_size = nblocks * mfun->block_size;
+
+	rc = usbmast_run_cmd(mfun, &cmd);
 
         if (rc != EOK) {
-		usb_log_error("Read (12) failed, device %s: %s.\n",
-		   mfun->mdev->ddf_dev->name, str_error(rc));
-		return rc;
-	}
-
-	if (data_len < nblocks * mfun->block_size) {
+		usb_log_error("Read (10) transport failed, device %s: %s.\n",
+		   mfun->mdev->ddf_dev->name, str_error(rc));
+		return rc;
+	}
+
+	if (cmd.status != CMDS_GOOD) {
+		usb_log_error("Read (10) command failed, device %s.\n",
+		   mfun->mdev->ddf_dev->name);
+		return EIO;
+	}
+
+	if (cmd.rcvd_size < nblocks * mfun->block_size) {
 		usb_log_error("SCSI Read response too short (%zu).\n",
-		    data_len);
+		    cmd.rcvd_size);
 		return EIO;
 	}
@@ -250,6 +345,6 @@
     const void *data)
 {
-	scsi_cdb_write_12_t cdb;
-	size_t sent_len;
+	scsi_cmd_t cmd;
+	scsi_cdb_write_10_t cdb;
 	int rc;
 
@@ -257,24 +352,29 @@
 		return ELIMIT;
 
-	if ((uint64_t)nblocks * mfun->block_size > UINT32_MAX)
+	if (nblocks > UINT16_MAX)
 		return ELIMIT;
 
 	memset(&cdb, 0, sizeof(cdb));
-	cdb.op_code = SCSI_CMD_WRITE_12;
+	cdb.op_code = SCSI_CMD_WRITE_10;
 	cdb.lba = host2uint32_t_be(ba);
-	cdb.xfer_len = host2uint32_t_be(nblocks);
-
-	rc = usb_massstor_data_out(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
-	    sizeof(cdb), data, nblocks * mfun->block_size, &sent_len);
+	cdb.xfer_len = host2uint16_t_be(nblocks);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_out = data;
+	cmd.data_out_size = nblocks * mfun->block_size;
+
+	rc = usbmast_run_cmd(mfun, &cmd);
 
         if (rc != EOK) {
-		usb_log_error("Write (12) failed, device %s: %s.\n",
-		   mfun->mdev->ddf_dev->name, str_error(rc));
-		return rc;
-	}
-
-	if (sent_len < nblocks * mfun->block_size) {
-		usb_log_error("SCSI Write not all bytes transferred (%zu).\n",
-		    sent_len);
+		usb_log_error("Write (10) transport failed, device %s: %s.\n",
+		   mfun->mdev->ddf_dev->name, str_error(rc));
+		return rc;
+	}
+
+	if (cmd.status != CMDS_GOOD) {
+		usb_log_error("Write (10) command failed, device %s.\n",
+		   mfun->mdev->ddf_dev->name);
 		return EIO;
 	}
Index: uspace/lib/block/libblock.c
===================================================================
--- uspace/lib/block/libblock.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/block/libblock.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -258,5 +258,5 @@
 static hash_index_t cache_hash(unsigned long *key)
 {
-	return *key & (CACHE_BUCKETS - 1);
+	return MERGE_LOUP32(key[0], key[1]) & (CACHE_BUCKETS - 1);
 }
 
@@ -264,5 +264,5 @@
 {
 	block_t *b = hash_table_get_instance(item, block_t, hash_link);
-	return b->lba == *key;
+	return b->lba == MERGE_LOUP32(key[0], key[1]);
 }
 
@@ -305,5 +305,5 @@
 	cache->blocks_cluster = cache->lblock_size / devcon->pblock_size;
 
-	if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1,
+	if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 2,
 	    &cache_ops)) {
 		free(cache);
@@ -344,6 +344,9 @@
 		}
 
-		unsigned long key = b->lba;
-		hash_table_remove(&cache->block_hash, &key, 1);
+		unsigned long key[2] = {
+			LOWER32(b->lba),
+			UPPER32(b->lba)
+		};
+		hash_table_remove(&cache->block_hash, key, 2);
 		
 		free(b->data);
@@ -398,5 +401,9 @@
 	block_t *b;
 	link_t *l;
-	unsigned long key = ba;
+	unsigned long key[2] = {
+		LOWER32(ba),
+		UPPER32(ba)
+	};
+
 	int rc;
 	
@@ -413,5 +420,5 @@
 
 	fibril_mutex_lock(&cache->lock);
-	l = hash_table_find(&cache->block_hash, &key);
+	l = hash_table_find(&cache->block_hash, key);
 	if (l) {
 found:
@@ -451,5 +458,4 @@
 			 * Try to recycle a block from the free list.
 			 */
-			unsigned long temp_key;
 recycle:
 			if (list_empty(&cache->free_list)) {
@@ -499,5 +505,5 @@
 					goto retry;
 				}
-				l = hash_table_find(&cache->block_hash, &key);
+				l = hash_table_find(&cache->block_hash, key);
 				if (l) {
 					/*
@@ -522,6 +528,9 @@
 			 */
 			list_remove(&b->free_link);
-			temp_key = b->lba;
-			hash_table_remove(&cache->block_hash, &temp_key, 1);
+			unsigned long temp_key[2] = {
+				LOWER32(b->lba),
+				UPPER32(b->lba)
+			};
+			hash_table_remove(&cache->block_hash, temp_key, 2);
 		}
 
@@ -531,5 +540,5 @@
 		b->lba = ba;
 		b->pba = ba_ltop(devcon, b->lba);
-		hash_table_insert(&cache->block_hash, &key, &b->hash_link);
+		hash_table_insert(&cache->block_hash, key, &b->hash_link);
 
 		/*
@@ -643,6 +652,9 @@
 			 * Take the block out of the cache and free it.
 			 */
-			unsigned long key = block->lba;
-			hash_table_remove(&cache->block_hash, &key, 1);
+			unsigned long key[2] = {
+				LOWER32(block->lba),
+				UPPER32(block->lba)
+			};
+			hash_table_remove(&cache->block_hash, key, 2);
 			fibril_mutex_unlock(&block->lock);
 			free(block->data);
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/c/Makefile	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -59,6 +59,4 @@
 -include arch/$(UARCH)/Makefile.inc
 
-EXTRA_CFLAGS += -I../../srv/loader/include
-
 GENERIC_SOURCES = \
 	generic/libc.c \
@@ -71,4 +69,5 @@
 	generic/device/hw_res.c \
 	generic/device/char_dev.c \
+	generic/elf/elf_load.c \
 	generic/event.c \
 	generic/errno.c \
@@ -134,5 +133,4 @@
 		generic/dlfcn.c \
 		generic/rtld/rtld.c \
-		generic/rtld/elf_load.c \
 		generic/rtld/dynamic.c \
 		generic/rtld/module.c \
Index: uspace/lib/c/arch/abs32le/include/elf_linux.h
===================================================================
--- uspace/lib/c/arch/abs32le/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/arch/abs32le/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup libcabs32le
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_abs32le_ELF_LINUX_H_
+#define LBIC_abs32le_ELF_LINUX_H_
+
+#include <libarch/istate.h>
+#include <sys/types.h>
+
+typedef struct {
+} elf_regs_t;
+
+static inline void istate_to_elf_regs(istate_t *istate, elf_regs_t *elf_regs)
+{
+	(void) istate; (void) elf_regs;
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/amd64/include/elf_linux.h
===================================================================
--- uspace/lib/c/arch/amd64/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/arch/amd64/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup libcamd64
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_amd64_ELF_LINUX_H_
+#define LBIC_amd64_ELF_LINUX_H_
+
+#include <libarch/istate.h>
+#include <sys/types.h>
+
+typedef struct {
+	/* TODO */
+	uint64_t pad[16];
+} elf_regs_t;
+
+static inline void istate_to_elf_regs(istate_t *istate, elf_regs_t *elf_regs)
+{
+	/* TODO */
+	(void) istate; (void) elf_regs;
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/arm32/include/elf_linux.h
===================================================================
--- uspace/lib/c/arch/arm32/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/arch/arm32/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup libcarm32
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_arm32_ELF_LINUX_H_
+#define LBIC_arm32_ELF_LINUX_H_
+
+#include <libarch/istate.h>
+#include <sys/types.h>
+
+typedef struct {
+	/* TODO */
+	uint32_t pad[16];
+} elf_regs_t;
+
+static inline void istate_to_elf_regs(istate_t *istate, elf_regs_t *elf_regs)
+{
+	/* TODO */
+	(void) istate; (void) elf_regs;
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/ia32/include/elf_linux.h
===================================================================
--- uspace/lib/c/arch/ia32/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/arch/ia32/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup libcia32
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_ia32_ELF_LINUX_H_
+#define LBIC_ia32_ELF_LINUX_H_
+
+#include <libarch/istate.h>
+#include <sys/types.h>
+
+typedef struct {
+	uint32_t ebx;
+	uint32_t ecx;
+	uint32_t edx;
+	uint32_t esi;
+	uint32_t edi;
+	uint32_t ebp;
+	uint32_t eax;
+	uint32_t ds;
+	uint32_t es;
+	uint32_t fs;
+	uint32_t gs;
+	uint32_t old_eax;
+	uint32_t eip;
+	uint32_t cs;
+	uint32_t eflags;
+	uint32_t esp;
+	uint32_t ss;
+} elf_regs_t;
+
+static inline void istate_to_elf_regs(istate_t *istate, elf_regs_t *elf_regs)
+{
+	elf_regs->ebx = istate->ebx;
+	elf_regs->ecx = istate->ecx;
+	elf_regs->edx = istate->edx;
+	elf_regs->esi = istate->esi;
+	elf_regs->edi = istate->edi;
+	elf_regs->ebp = istate->ebp;
+	elf_regs->eax = istate->eax;
+
+	elf_regs->ds = istate->ds;
+	elf_regs->es = istate->es;
+	elf_regs->fs = istate->fs;
+	elf_regs->gs = istate->gs;
+
+	elf_regs->old_eax = 0;
+	elf_regs->eip = istate->eip;
+	elf_regs->cs = istate->cs;
+	elf_regs->eflags = istate->eflags;
+	elf_regs->esp = istate->esp;
+	elf_regs->ss = istate->ss;
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/ia64/include/elf_linux.h
===================================================================
--- uspace/lib/c/arch/ia64/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/arch/ia64/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup libcia64
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_ia64_ELF_LINUX_H_
+#define LBIC_ia64_ELF_LINUX_H_
+
+#include <libarch/istate.h>
+#include <sys/types.h>
+
+typedef struct {
+	/* TODO */
+	uint64_t pad[16];
+} elf_regs_t;
+
+static inline void istate_to_elf_regs(istate_t *istate, elf_regs_t *elf_regs)
+{
+	/* TODO */
+	(void) istate; (void) elf_regs;
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/mips32/include/elf_linux.h
===================================================================
--- uspace/lib/c/arch/mips32/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/arch/mips32/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup libcmips32
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_mips32_ELF_LINUX_H_
+#define LBIC_mips32_ELF_LINUX_H_
+
+#include <libarch/istate.h>
+#include <sys/types.h>
+
+typedef struct {
+	/* TODO */
+	uint32_t pad[16];
+} elf_regs_t;
+
+static inline void istate_to_elf_regs(istate_t *istate, elf_regs_t *elf_regs)
+{
+	/* TODO */
+	(void) istate; (void) elf_regs;
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/mips32eb/include/elf_linux.h
===================================================================
--- uspace/lib/c/arch/mips32eb/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/arch/mips32eb/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,1 @@
+../../mips32/include/elf_linux.h
Index: uspace/lib/c/arch/mips64/include/elf_linux.h
===================================================================
--- uspace/lib/c/arch/mips64/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/arch/mips64/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup libcmips64
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_mips64_ELF_LINUX_H_
+#define LBIC_mips64_ELF_LINUX_H_
+
+#include <libarch/istate.h>
+#include <sys/types.h>
+
+typedef struct {
+	/* TODO */
+	uint64_t pad[16];
+} elf_regs_t;
+
+static inline void istate_to_elf_regs(istate_t *istate, elf_regs_t *elf_regs)
+{
+	/* TODO */
+	(void) istate; (void) elf_regs;
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/ppc32/include/elf_linux.h
===================================================================
--- uspace/lib/c/arch/ppc32/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/arch/ppc32/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup libcppc32
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_ppc32_ELF_LINUX_H_
+#define LBIC_ppc32_ELF_LINUX_H_
+
+#include <libarch/istate.h>
+#include <sys/types.h>
+
+typedef struct {
+	/* TODO */
+	uint32_t pad[16];
+} elf_regs_t;
+
+static inline void istate_to_elf_regs(istate_t *istate, elf_regs_t *elf_regs)
+{
+	/* TODO */
+	(void) istate; (void) elf_regs;
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/arch/sparc64/include/elf_linux.h
===================================================================
--- uspace/lib/c/arch/sparc64/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/arch/sparc64/include/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup libcsparc64
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_sparc64_ELF_LINUX_H_
+#define LBIC_sparc64_ELF_LINUX_H_
+
+#include <libarch/istate.h>
+#include <sys/types.h>
+
+typedef struct {
+	/* TODO */
+	uint64_t pad[16];
+} elf_regs_t;
+
+static inline void istate_to_elf_regs(istate_t *istate, elf_regs_t *elf_regs)
+{
+	/* TODO */
+	(void) istate; (void) elf_regs;
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/generic/elf/elf_load.c
===================================================================
--- uspace/lib/c/generic/elf/elf_load.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/generic/elf/elf_load.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 2006 Sergey Bondari
+ * Copyright (c) 2006 Jakub Jermar
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup generic
+ * @{
+ */
+
+/**
+ * @file
+ * @brief	Userspace ELF loader.
+ *
+ * This module allows loading ELF binaries (both executables and
+ * shared objects) from VFS. The current implementation allocates
+ * anonymous memory, fills it with segment data and then adjusts
+ * the memory areas' flags to the final value. In the future,
+ * the segments will be mapped directly from the file.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <align.h>
+#include <assert.h>
+#include <as.h>
+#include <elf/elf.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <smc.h>
+#include <loader/pcb.h>
+#include <entry_point.h>
+
+#include <elf/elf_load.h>
+
+#define DPRINTF(...)
+
+static const char *error_codes[] = {
+	"no error",
+	"invalid image",
+	"address space error",
+	"incompatible image",
+	"unsupported image type",
+	"irrecoverable error"
+};
+
+static unsigned int elf_load(elf_ld_t *elf, size_t so_bias);
+static int segment_header(elf_ld_t *elf, elf_segment_header_t *entry);
+static int section_header(elf_ld_t *elf, elf_section_header_t *entry);
+static int load_segment(elf_ld_t *elf, elf_segment_header_t *entry);
+
+/** Load ELF binary from a file.
+ *
+ * Load an ELF binary from the specified file. If the file is
+ * an executable program, it is loaded unbiased. If it is a shared
+ * object, it is loaded with the bias @a so_bias. Some information
+ * extracted from the binary is stored in a elf_info_t structure
+ * pointed to by @a info.
+ *
+ * @param file_name Path to the ELF file.
+ * @param so_bias   Bias to use if the file is a shared object.
+ * @param info      Pointer to a structure for storing information
+ *                  extracted from the binary.
+ *
+ * @return EOK on success or negative error code.
+ *
+ */
+int elf_load_file(const char *file_name, size_t so_bias, eld_flags_t flags,
+    elf_info_t *info)
+{
+	elf_ld_t elf;
+
+	int fd;
+	int rc;
+	
+	fd = open(file_name, O_RDONLY);
+	if (fd < 0) {
+		DPRINTF("failed opening file\n");
+		return -1;
+	}
+
+	elf.fd = fd;
+	elf.info = info;
+	elf.flags = flags;
+
+	rc = elf_load(&elf, so_bias);
+
+	close(fd);
+
+	return rc;
+}
+
+/** Create the program control block (PCB).
+ *
+ * Fills the program control block @a pcb with information from
+ * @a info.
+ *
+ * @param info	Program info structure
+ * @return EOK on success or negative error code
+ */
+void elf_create_pcb(elf_info_t *info, pcb_t *pcb)
+{
+	pcb->entry = info->entry;
+	pcb->dynamic = info->dynamic;
+	pcb->rtld_runtime = NULL;
+}
+
+
+/** Load an ELF binary.
+ *
+ * The @a elf structure contains the loader state, including
+ * an open file, from which the binary will be loaded,
+ * a pointer to the @c info structure etc.
+ *
+ * @param elf		Pointer to loader state buffer.
+ * @param so_bias	Bias to use if the file is a shared object.
+ * @return EE_OK on success or EE_xx error code.
+ */
+static unsigned int elf_load(elf_ld_t *elf, size_t so_bias)
+{
+	elf_header_t header_buf;
+	elf_header_t *header = &header_buf;
+	int i, rc;
+
+	rc = read_all(elf->fd, header, sizeof(elf_header_t));
+	if (rc != sizeof(elf_header_t)) {
+		DPRINTF("Read error.\n"); 
+		return EE_INVALID;
+	}
+
+	elf->header = header;
+
+	/* Identify ELF */
+	if (header->e_ident[EI_MAG0] != ELFMAG0 ||
+	    header->e_ident[EI_MAG1] != ELFMAG1 || 
+	    header->e_ident[EI_MAG2] != ELFMAG2 ||
+	    header->e_ident[EI_MAG3] != ELFMAG3) {
+		DPRINTF("Invalid header.\n");
+		return EE_INVALID;
+	}
+	
+	/* Identify ELF compatibility */
+	if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
+	    header->e_machine != ELF_MACHINE || 
+	    header->e_ident[EI_VERSION] != EV_CURRENT ||
+	    header->e_version != EV_CURRENT ||
+	    header->e_ident[EI_CLASS] != ELF_CLASS) {
+		DPRINTF("Incompatible data/version/class.\n");
+		return EE_INCOMPATIBLE;
+	}
+
+	if (header->e_phentsize != sizeof(elf_segment_header_t)) {
+		DPRINTF("e_phentsize:%d != %d\n", header->e_phentsize,
+		    sizeof(elf_segment_header_t));
+		return EE_INCOMPATIBLE;
+	}
+
+	if (header->e_shentsize != sizeof(elf_section_header_t)) {
+		DPRINTF("e_shentsize:%d != %d\n", header->e_shentsize,
+		    sizeof(elf_section_header_t));
+		return EE_INCOMPATIBLE;
+	}
+
+	/* Check if the object type is supported. */
+	if (header->e_type != ET_EXEC && header->e_type != ET_DYN) {
+		DPRINTF("Object type %d is not supported\n", header->e_type);
+		return EE_UNSUPPORTED;
+	}
+
+	/* Shared objects can be loaded with a bias */
+	if (header->e_type == ET_DYN)
+		elf->bias = so_bias;
+	else
+		elf->bias = 0;
+
+	elf->info->interp = NULL;
+	elf->info->dynamic = NULL;
+
+	/* Walk through all segment headers and process them. */
+	for (i = 0; i < header->e_phnum; i++) {
+		elf_segment_header_t segment_hdr;
+
+		/* Seek to start of segment header */
+		lseek(elf->fd, header->e_phoff
+		        + i * sizeof(elf_segment_header_t), SEEK_SET);
+
+		rc = read_all(elf->fd, &segment_hdr,
+		    sizeof(elf_segment_header_t));
+		if (rc != sizeof(elf_segment_header_t)) {
+			DPRINTF("Read error.\n");
+			return EE_INVALID;
+		}
+
+		rc = segment_header(elf, &segment_hdr);
+		if (rc != EE_OK)
+			return rc;
+	}
+
+	DPRINTF("Parse sections.\n");
+
+	/* Inspect all section headers and proccess them. */
+	for (i = 0; i < header->e_shnum; i++) {
+		elf_section_header_t section_hdr;
+
+		/* Seek to start of section header */
+		lseek(elf->fd, header->e_shoff
+		    + i * sizeof(elf_section_header_t), SEEK_SET);
+
+		rc = read_all(elf->fd, &section_hdr,
+		    sizeof(elf_section_header_t));
+		if (rc != sizeof(elf_section_header_t)) {
+			DPRINTF("Read error.\n");
+			return EE_INVALID;
+		}
+
+		rc = section_header(elf, &section_hdr);
+		if (rc != EE_OK)
+			return rc;
+	}
+
+	elf->info->entry =
+	    (entry_point_t)((uint8_t *)header->e_entry + elf->bias);
+
+	DPRINTF("Done.\n");
+
+	return EE_OK;
+}
+
+/** Print error message according to error code.
+ *
+ * @param rc Return code returned by elf_load().
+ *
+ * @return NULL terminated description of error.
+ */
+const char *elf_error(unsigned int rc)
+{
+	assert(rc < sizeof(error_codes) / sizeof(char *));
+
+	return error_codes[rc];
+}
+
+/** Process segment header.
+ *
+ * @param entry	Segment header.
+ *
+ * @return EE_OK on success, error code otherwise.
+ */
+static int segment_header(elf_ld_t *elf, elf_segment_header_t *entry)
+{
+	switch (entry->p_type) {
+	case PT_NULL:
+	case PT_PHDR:
+	case PT_NOTE:
+		break;
+	case PT_LOAD:
+		return load_segment(elf, entry);
+		break;
+	case PT_INTERP:
+		/* Assume silently interp == "/app/dload" */
+		elf->info->interp = "/app/dload";
+		break;
+	case PT_DYNAMIC:
+		/* Record pointer to dynamic section into info structure */
+		elf->info->dynamic =
+		    (void *)((uint8_t *)entry->p_vaddr + elf->bias);
+		DPRINTF("dynamic section found at 0x%x\n",
+			(uintptr_t)elf->info->dynamic);
+		break;
+	case 0x70000000:
+		/* FIXME: MIPS reginfo */
+		break;
+	case PT_SHLIB:
+//	case PT_LOPROC:
+//	case PT_HIPROC:
+	default:
+		DPRINTF("Segment p_type %d unknown.\n", entry->p_type);
+		return EE_UNSUPPORTED;
+		break;
+	}
+	return EE_OK;
+}
+
+/** Load segment described by program header entry.
+ *
+ * @param elf	Loader state.
+ * @param entry Program header entry describing segment to be loaded.
+ *
+ * @return EE_OK on success, error code otherwise.
+ */
+int load_segment(elf_ld_t *elf, elf_segment_header_t *entry)
+{
+	void *a;
+	int flags = 0;
+	uintptr_t bias;
+	uintptr_t base;
+	void *seg_ptr;
+	uintptr_t seg_addr;
+	size_t mem_sz;
+	ssize_t rc;
+
+	bias = elf->bias;
+
+	seg_addr = entry->p_vaddr + bias;
+	seg_ptr = (void *) seg_addr;
+
+	DPRINTF("Load segment at addr %p, size 0x%x\n", (void *) seg_addr,
+		entry->p_memsz);
+
+	if (entry->p_align > 1) {
+		if ((entry->p_offset % entry->p_align) !=
+		    (seg_addr % entry->p_align)) {
+			DPRINTF("Align check 1 failed offset%%align=%d, "
+			    "vaddr%%align=%d\n",
+			    entry->p_offset % entry->p_align,
+			    seg_addr % entry->p_align
+			);
+			return EE_INVALID;
+		}
+	}
+
+	/* Final flags that will be set for the memory area */
+
+	if (entry->p_flags & PF_X)
+		flags |= AS_AREA_EXEC;
+	if (entry->p_flags & PF_W)
+		flags |= AS_AREA_WRITE;
+	if (entry->p_flags & PF_R)
+		flags |= AS_AREA_READ;
+	flags |= AS_AREA_CACHEABLE;
+	
+	base = ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE);
+	mem_sz = entry->p_memsz + (entry->p_vaddr - base);
+
+	DPRINTF("Map to seg_addr=%p-%p.\n", (void *) seg_addr,
+	    (void *) (entry->p_vaddr + bias +
+	    ALIGN_UP(entry->p_memsz, PAGE_SIZE)));
+
+	/*
+	 * For the course of loading, the area needs to be readable
+	 * and writeable.
+	 */
+	a = as_area_create((uint8_t *)base + bias, mem_sz,
+	    AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE);
+	if (a == (void *)(-1)) {
+		DPRINTF("memory mapping failed (0x%x, %d)\n",
+			base+bias, mem_sz);
+		return EE_MEMORY;
+	}
+
+	DPRINTF("as_area_create(%p, %#zx, %d) -> %p\n",
+	    (void *) (base + bias), mem_sz, flags, (void *) a);
+
+	/*
+	 * Load segment data
+	 */
+	rc = lseek(elf->fd, entry->p_offset, SEEK_SET);
+	if (rc < 0) {
+		printf("seek error\n");
+		return EE_INVALID;
+	}
+
+/*	rc = read(fd, (void *)(entry->p_vaddr + bias), entry->p_filesz);
+	if (rc < 0) { printf("read error\n"); return EE_INVALID; }*/
+
+	/* Long reads are not possible yet. Load segment piecewise. */
+
+	unsigned left, now;
+	uint8_t *dp;
+
+	left = entry->p_filesz;
+	dp = seg_ptr;
+
+	while (left > 0) {
+		now = 16384;
+		if (now > left) now = left;
+
+		rc = read_all(elf->fd, dp, now);
+
+		if (rc != (ssize_t) now) { 
+			DPRINTF("Read error.\n");
+			return EE_INVALID;
+		}
+
+		left -= now;
+		dp += now;
+	}
+
+	/*
+	 * The caller wants to modify the segments first. He will then
+	 * need to set the right access mode and ensure SMC coherence.
+	 */
+	if ((elf->flags & ELDF_RW) != 0) return EE_OK;
+
+//	printf("set area flags to %d\n", flags);
+	rc = as_area_change_flags(seg_ptr, flags);
+	if (rc != 0) {
+		DPRINTF("Failed to set memory area flags.\n");
+		return EE_MEMORY;
+	}
+
+	if (flags & AS_AREA_EXEC) {
+		/* Enforce SMC coherence for the segment */
+		if (smc_coherence(seg_ptr, entry->p_filesz))
+			return EE_MEMORY;
+	}
+
+	return EE_OK;
+}
+
+/** Process section header.
+ *
+ * @param elf	Loader state.
+ * @param entry Segment header.
+ *
+ * @return EE_OK on success, error code otherwise.
+ */
+static int section_header(elf_ld_t *elf, elf_section_header_t *entry)
+{
+	switch (entry->sh_type) {
+	case SHT_PROGBITS:
+		if (entry->sh_flags & SHF_TLS) {
+			/* .tdata */
+		}
+		break;
+	case SHT_NOBITS:
+		if (entry->sh_flags & SHF_TLS) {
+			/* .tbss */
+		}
+		break;
+	case SHT_DYNAMIC:
+		/* Record pointer to dynamic section into info structure */
+		elf->info->dynamic =
+		    (void *)((uint8_t *)entry->sh_addr + elf->bias);
+		DPRINTF("Dynamic section found at %p.\n",
+		    (void *) elf->info->dynamic);
+		break;
+	default:
+		break;
+	}
+	
+	return EE_OK;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/io/io.c
===================================================================
--- uspace/lib/c/generic/io/io.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/c/generic/io/io.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -594,9 +594,10 @@
 		}
 		
-		buf += now;
+		data += now;
 		stream->buf_head += now;
 		buf_free -= now;
 		bytes_left -= now;
 		total_written += now;
+		stream->buf_state = _bs_write;
 		
 		if (buf_free == 0) {
@@ -606,7 +607,4 @@
 		}
 	}
-	
-	if (total_written > 0)
-		stream->buf_state = _bs_write;
 
 	if (need_flush)
Index: pace/lib/c/generic/rtld/elf_load.c
===================================================================
--- uspace/lib/c/generic/rtld/elf_load.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ 	(revision )
@@ -1,1 +1,0 @@
-../../../../srv/loader/elf_load.c
Index: uspace/lib/c/generic/rtld/module.c
===================================================================
--- uspace/lib/c/generic/rtld/module.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/c/generic/rtld/module.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -35,10 +35,11 @@
  */
 
+#include <adt/list.h>
+#include <elf/elf_load.h>
+#include <fcntl.h>
+#include <loader/pcb.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <fcntl.h>
-#include <adt/list.h>
-#include <loader/pcb.h>
 
 #include <rtld/rtld.h>
@@ -47,5 +48,4 @@
 #include <rtld/rtld_arch.h>
 #include <rtld/module.h>
-#include <elf_load.h>
 
 /** (Eagerly) process all relocation tables in a module.
@@ -93,7 +93,4 @@
 module_t *module_find(const char *name)
 {
-	link_t *head = &runtime_env->modules_head;
-
-	link_t *cur;
 	module_t *m;
 	const char *p, *soname;
@@ -110,6 +107,5 @@
 
 	/* Traverse list of all modules. Not extremely fast, but simple */
-	DPRINTF("head = %p\n", head);
-	for (cur = head->next; cur != head; cur = cur->next) {
+	list_foreach(runtime_env->modules, cur) {
 		DPRINTF("cur = %p\n", cur);
 		m = list_get_instance(cur, module_t, modules_link);
@@ -177,5 +173,5 @@
 
 	/* Insert into the list of loaded modules */
-	list_append(&m->modules_link, &runtime_env->modules_head);
+	list_append(&m->modules_link, &runtime_env->modules);
 
 	return m;
@@ -249,10 +245,7 @@
 void modules_process_relocs(module_t *start)
 {
-	link_t *head = &runtime_env->modules_head;
-
-	link_t *cur;
-	module_t *m;
-
-	for (cur = head->next; cur != head; cur = cur->next) {
+	module_t *m;
+
+	list_foreach(runtime_env->modules, cur) {
 		m = list_get_instance(cur, module_t, modules_link);
 
@@ -268,10 +261,7 @@
 void modules_untag(void)
 {
-	link_t *head = &runtime_env->modules_head;
-
-	link_t *cur;
-	module_t *m;
-
-	for (cur = head->next; cur != head; cur = cur->next) {
+	module_t *m;
+
+	list_foreach(runtime_env->modules, cur) {
 		m = list_get_instance(cur, module_t, modules_link);
 		m->bfs_tag = false;
Index: uspace/lib/c/generic/rtld/rtld.c
===================================================================
--- uspace/lib/c/generic/rtld/rtld.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/c/generic/rtld/rtld.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -44,5 +44,5 @@
 {
 	runtime_env = &rt_env_static;
-	list_initialize(&runtime_env->modules_head);
+	list_initialize(&runtime_env->modules);
 	runtime_env->next_bias = 0x2000000;
 	runtime_env->program = NULL;
Index: uspace/lib/c/generic/rtld/symbol.c
===================================================================
--- uspace/lib/c/generic/rtld/symbol.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/c/generic/rtld/symbol.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -38,8 +38,8 @@
 #include <stdlib.h>
 
+#include <elf/elf.h>
 #include <rtld/rtld.h>
 #include <rtld/rtld_debug.h>
 #include <rtld/symbol.h>
-#include <elf.h>
 
 /*
@@ -118,5 +118,5 @@
 	module_t *m, *dm;
 	elf_symbol_t *sym, *s;
-	link_t queue_head;
+	list_t queue;
 	size_t i;
 
@@ -132,7 +132,7 @@
 
 	/* Insert root (the program) into the queue and tag it */
-	list_initialize(&queue_head);
+	list_initialize(&queue);
 	start->bfs_tag = true;
-	list_append(&start->queue_link, &queue_head);
+	list_append(&start->queue_link, &queue);
 
 	/* If the symbol is found, it will be stored in 'sym' */
@@ -140,7 +140,7 @@
 
 	/* While queue is not empty */
-	while (!list_empty(&queue_head)) {
+	while (!list_empty(&queue)) {
 		/* Pop first element from the queue */
-		m = list_get_instance(queue_head.next, module_t, queue_link);
+		m = list_get_instance(list_first(&queue), module_t, queue_link);
 		list_remove(&m->queue_link);
 
@@ -162,5 +162,5 @@
 			if (dm->bfs_tag == false) {
 				dm->bfs_tag = true;
-				list_append(&dm->queue_link, &queue_head);
+				list_append(&dm->queue_link, &queue);
 			}
 		}
@@ -168,6 +168,6 @@
 
 	/* Empty the queue so that we leave it in a clean state */
-	while (!list_empty(&queue_head))
-		list_remove(queue_head.next);
+	while (!list_empty(&queue))
+		list_remove(list_first(&queue));
 
 	if (!sym) {
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -417,4 +417,66 @@
 }
 
+/** Read entire buffer.
+ *
+ * In face of short reads this function continues reading until either
+ * the entire buffer is read or no more data is available (at end of file).
+ *
+ * @param fildes	File descriptor
+ * @param buf		Buffer, @a nbytes bytes long
+ * @param nbytes	Number of bytes to read
+ *
+ * @return		On success, positive number of bytes read.
+ *			On failure, negative error code from read().
+ */
+ssize_t read_all(int fildes, void *buf, size_t nbyte)
+{
+	ssize_t cnt = 0;
+	size_t nread = 0;
+	uint8_t *bp = (uint8_t *) buf;
+
+	do {
+		bp += cnt;
+		nread += cnt;
+		cnt = read(fildes, bp, nbyte - nread);
+	} while (cnt > 0 && (nbyte - nread - cnt) > 0);
+
+	if (cnt < 0)
+		return cnt;
+
+	return nread + cnt;
+}
+
+/** Write entire buffer.
+ *
+ * This function fails if it cannot write exactly @a len bytes to the file.
+ *
+ * @param fildes	File descriptor
+ * @param buf		Data, @a nbytes bytes long
+ * @param nbytes	Number of bytes to write
+ *
+ * @return		EOK on error, return value from write() if writing
+ *			failed.
+ */
+ssize_t write_all(int fildes, const void *buf, size_t nbyte)
+{
+	ssize_t cnt = 0;
+	ssize_t nwritten = 0;
+	const uint8_t *bp = (uint8_t *) buf;
+
+	do {
+		bp += cnt;
+		nwritten += cnt;
+		cnt = write(fildes, bp, nbyte - nwritten);
+	} while (cnt > 0 && ((ssize_t )nbyte - nwritten - cnt) > 0);
+
+	if (cnt < 0)
+		return cnt;
+
+	if ((ssize_t)nbyte - nwritten - cnt > 0)
+		return EIO;
+
+	return nbyte;
+}
+
 int fsync(int fildes)
 {
Index: uspace/lib/c/include/elf/elf.h
===================================================================
--- uspace/lib/c/include/elf/elf.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/include/elf/elf.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup generic
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_ELF_H_
+#define LIBC_ELF_H_
+
+#include <kernel/lib/elf.h>
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/elf/elf_linux.h
===================================================================
--- uspace/lib/c/include/elf/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/include/elf/elf_linux.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup generic
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_ELF_LINUX_H_
+#define LIBC_ELF_LINUX_H_
+
+#include <elf/elf.h>
+#include <libarch/elf_linux.h>
+
+/*
+ * Note types
+ */
+#define NT_PRSTATUS	1
+
+typedef int pid_t;
+typedef struct {
+	long tv_sec;
+	long tv_usec;
+} linux_timeval_t;
+
+typedef struct {
+	int sig_info[3];
+	short cursig;
+	unsigned long sigpend;
+	unsigned long sighold;
+	pid_t pid;
+	pid_t ppid;
+	pid_t pgrp;
+	pid_t sid;
+	linux_timeval_t pr_utime;
+	linux_timeval_t pr_stime;
+	linux_timeval_t pr_cutime;
+	linux_timeval_t pr_sid;
+	elf_regs_t regs;
+	int fpvalid;
+} elf_prstatus_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/elf/elf_load.h
===================================================================
--- uspace/lib/c/include/elf/elf_load.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/include/elf/elf_load.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2006 Sergey Bondari
+ * Copyright (c) 2008 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup generic
+ * @{
+ */
+/** @file
+ * @brief ELF loader structures and public functions.
+ */
+
+#ifndef ELF_LOAD_H_
+#define ELF_LOAD_H_
+
+#include <arch/elf.h>
+#include <elf/elf.h>
+#include <sys/types.h>
+#include <loader/pcb.h>
+
+/**
+ * ELF error return codes
+ */
+#define EE_OK			0	/* No error */
+#define EE_INVALID		1	/* Invalid ELF image */
+#define	EE_MEMORY		2	/* Cannot allocate address space */
+#define EE_INCOMPATIBLE		3	/* ELF image is not compatible with current architecture */
+#define EE_UNSUPPORTED		4	/* Non-supported ELF (e.g. dynamic ELFs) */
+#define EE_LOADER		5	/* The image is actually a program loader. */
+#define EE_IRRECOVERABLE	6
+
+typedef enum {
+	/** Leave all segments in RW access mode. */
+	ELDF_RW = 1
+} eld_flags_t;
+
+/**
+ * Some data extracted from the headers are stored here
+ */
+typedef struct {
+	/** Entry point */
+	entry_point_t entry;
+
+	/** ELF interpreter name or NULL if statically-linked */
+	const char *interp;
+
+	/** Pointer to the dynamic section */
+	void *dynamic;
+} elf_info_t;
+
+/**
+ * Holds information about an ELF binary being loaded.
+ */
+typedef struct {
+	/** Filedescriptor of the file from which we are loading */
+	int fd;
+
+	/** Difference between run-time addresses and link-time addresses */
+	uintptr_t bias;
+
+	/** Flags passed to the ELF loader. */
+	eld_flags_t flags;
+
+	/** A copy of the ELF file header */
+	elf_header_t *header;
+
+	/** Store extracted info here */
+	elf_info_t *info;
+} elf_ld_t;
+
+extern const char *elf_error(unsigned int);
+extern int elf_load_file(const char *, size_t, eld_flags_t, elf_info_t *);
+extern void elf_create_pcb(elf_info_t *, pcb_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/rtld/elf_dyn.h
===================================================================
--- uspace/lib/c/include/rtld/elf_dyn.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/c/include/rtld/elf_dyn.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -39,5 +39,5 @@
 #include <sys/types.h>
 
-#include <elf.h>
+#include <elf/elf.h>
 #include <libarch/rtld/elf_dyn.h>
 
Index: uspace/lib/c/include/rtld/rtld.h
===================================================================
--- uspace/lib/c/include/rtld/rtld.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/c/include/rtld/rtld.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -49,5 +49,5 @@
 
 	/** List of all loaded modules including rtld and the program */
-	link_t modules_head;
+	list_t modules;
 
 	/** Temporary hack to place each module at different address. */
Index: uspace/lib/c/include/rtld/symbol.h
===================================================================
--- uspace/lib/c/include/rtld/symbol.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/c/include/rtld/symbol.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -36,6 +36,6 @@
 #define LIBC_RTLD_SYMBOL_H_
 
+#include <elf/elf.h>
 #include <rtld/rtld.h>
-#include <elf.h>
 
 elf_symbol_t *symbol_bfs_find(const char *name, module_t *start, module_t **mod);
Index: uspace/lib/c/include/typedefs.h
===================================================================
--- uspace/lib/c/include/typedefs.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
+++ uspace/lib/c/include/typedefs.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/** @addtogroup generic
+ * @{
+ */
+/** @file
+ *
+ * This header allows including a kernel header using typedefs.h from
+ * libc. User-space code should use sys/types.h directly.
+ */
+
+#ifndef LIBC_TYPEDEFS_H_
+#define LIBC_TYPEDEFS_H_
+
+#include <sys/types.h>
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/unistd.h
===================================================================
--- uspace/lib/c/include/unistd.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/c/include/unistd.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -63,4 +63,7 @@
 extern ssize_t read(int, void *, size_t);
 
+extern ssize_t read_all(int, void *, size_t);
+extern ssize_t write_all(int, const void *, size_t);
+
 extern off64_t lseek(int, off64_t, int);
 extern int ftruncate(int, aoff64_t);
Index: uspace/lib/fs/libfs.c
===================================================================
--- uspace/lib/fs/libfs.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/fs/libfs.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -45,4 +45,5 @@
 #include <mem.h>
 #include <sys/stat.h>
+#include <stdlib.h>
 
 #define on_error(rc, action) \
@@ -61,4 +62,226 @@
 	} while (0)
 
+static fs_reg_t reg;
+
+static vfs_out_ops_t *vfs_out_ops = NULL;
+static libfs_ops_t *libfs_ops = NULL;
+
+static void libfs_mount(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
+static void libfs_unmount(libfs_ops_t *, ipc_callid_t, ipc_call_t *);
+static void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t,
+    ipc_call_t *);
+static void libfs_stat(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
+static void libfs_open_node(libfs_ops_t *, fs_handle_t, ipc_callid_t,
+    ipc_call_t *);
+
+static void vfs_out_mounted(ipc_callid_t rid, ipc_call_t *req)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	char *opts;
+	int rc;
+	
+	/* Accept the mount options. */
+	rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+
+	fs_index_t index;
+	aoff64_t size;
+	unsigned lnkcnt;
+	rc = vfs_out_ops->mounted(devmap_handle, opts, &index, &size, &lnkcnt);
+
+	if (rc == EOK)
+		async_answer_4(rid, EOK, index, LOWER32(size), UPPER32(size),
+		    lnkcnt);
+	else
+		async_answer_0(rid, rc);
+
+	free(opts);
+}
+
+static void vfs_out_mount(ipc_callid_t rid, ipc_call_t *req)
+{
+	libfs_mount(libfs_ops, reg.fs_handle, rid, req);
+}
+
+static void vfs_out_unmounted(ipc_callid_t rid, ipc_call_t *req)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	int rc; 
+
+	rc = vfs_out_ops->unmounted(devmap_handle);
+
+	async_answer_0(rid, rc);
+}
+
+static void vfs_out_unmount(ipc_callid_t rid, ipc_call_t *req)
+{
+		
+	libfs_unmount(libfs_ops, rid, req);
+}
+
+static void vfs_out_lookup(ipc_callid_t rid, ipc_call_t *req)
+{
+	libfs_lookup(libfs_ops, reg.fs_handle, rid, req);
+}
+
+static void vfs_out_read(ipc_callid_t rid, ipc_call_t *req)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
+	aoff64_t pos = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
+	    IPC_GET_ARG4(*req));
+	size_t rbytes;
+	int rc;
+
+	rc = vfs_out_ops->read(devmap_handle, index, pos, &rbytes);
+
+	if (rc == EOK)
+		async_answer_1(rid, EOK, rbytes);
+	else
+		async_answer_0(rid, rc);
+}
+
+static void vfs_out_write(ipc_callid_t rid, ipc_call_t *req)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
+	aoff64_t pos = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
+	    IPC_GET_ARG4(*req));
+	size_t wbytes;
+	aoff64_t nsize;
+	int rc;
+
+	rc = vfs_out_ops->write(devmap_handle, index, pos, &wbytes, &nsize);
+
+	if (rc == EOK)
+		async_answer_3(rid, EOK, wbytes, LOWER32(nsize), UPPER32(nsize));
+	else
+		async_answer_0(rid, rc);
+}
+
+static void vfs_out_truncate(ipc_callid_t rid, ipc_call_t *req)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
+	aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
+	    IPC_GET_ARG4(*req));
+	int rc;
+
+	rc = vfs_out_ops->truncate(devmap_handle, index, size);
+
+	async_answer_0(rid, rc);
+}
+
+static void vfs_out_close(ipc_callid_t rid, ipc_call_t *req)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
+	int rc;
+
+	rc = vfs_out_ops->close(devmap_handle, index);
+
+	async_answer_0(rid, rc);
+}
+
+static void vfs_out_destroy(ipc_callid_t rid, ipc_call_t *req)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
+	int rc;
+
+	rc = vfs_out_ops->destroy(devmap_handle, index);
+
+	async_answer_0(rid, rc);
+}
+
+static void vfs_out_open_node(ipc_callid_t rid, ipc_call_t *req)
+{
+	libfs_open_node(libfs_ops, reg.fs_handle, rid, req);
+}
+
+static void vfs_out_stat(ipc_callid_t rid, ipc_call_t *req)
+{
+	libfs_stat(libfs_ops, reg.fs_handle, rid, req);
+}
+
+static void vfs_out_sync(ipc_callid_t rid, ipc_call_t *req)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
+	int rc;
+
+	rc = vfs_out_ops->sync(devmap_handle, index);
+
+	async_answer_0(rid, rc);
+}
+
+static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	if (iid) {
+		/*
+		 * This only happens for connections opened by
+		 * IPC_M_CONNECT_ME_TO calls as opposed to callback connections
+		 * created by IPC_M_CONNECT_TO_ME.
+		 */
+		async_answer_0(iid, EOK);
+	}
+	
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call))
+			return;
+		
+		switch (IPC_GET_IMETHOD(call)) {
+		case VFS_OUT_MOUNTED:
+			vfs_out_mounted(callid, &call);
+			break;
+		case VFS_OUT_MOUNT:
+			vfs_out_mount(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNTED:
+			vfs_out_unmounted(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNT:
+			vfs_out_unmount(callid, &call);
+			break;
+		case VFS_OUT_LOOKUP:
+			vfs_out_lookup(callid, &call);
+			break;
+		case VFS_OUT_READ:
+			vfs_out_read(callid, &call);
+			break;
+		case VFS_OUT_WRITE:
+			vfs_out_write(callid, &call);
+			break;
+		case VFS_OUT_TRUNCATE:
+			vfs_out_truncate(callid, &call);
+			break;
+		case VFS_OUT_CLOSE:
+			vfs_out_close(callid, &call);
+			break;
+		case VFS_OUT_DESTROY:
+			vfs_out_destroy(callid, &call);
+			break;
+		case VFS_OUT_OPEN_NODE:
+			vfs_out_open_node(callid, &call);
+			break;
+		case VFS_OUT_STAT:
+			vfs_out_stat(callid, &call);
+			break;
+		case VFS_OUT_SYNC:
+			vfs_out_sync(callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+	}
+}
+
 /** Register file system server.
  *
@@ -68,16 +291,14 @@
  *
  * @param sess Session for communication with VFS.
- * @param reg  File system registration structure. It will be
- *             initialized by this function.
  * @param info VFS info structure supplied by the file system
  *             implementation.
- * @param conn Connection fibril for handling all calls originating in
- *             VFS.
+ * @param vops Address of the vfs_out_ops_t structure.
+ * @param lops Address of the libfs_ops_t structure.
  *
  * @return EOK on success or a non-zero error code on errror.
  *
  */
-int fs_register(async_sess_t *sess, fs_reg_t *reg, vfs_info_t *info,
-    async_client_conn_t conn)
+int fs_register(async_sess_t *sess, vfs_info_t *info, vfs_out_ops_t *vops,
+    libfs_ops_t *lops)
 {
 	/*
@@ -104,13 +325,19 @@
 	
 	/*
+	 * Set VFS_OUT and libfs operations.
+	 */
+	vfs_out_ops = vops;
+	libfs_ops = lops;
+
+	/*
 	 * Ask VFS for callback connection.
 	 */
-	async_connect_to_me(exch, 0, 0, 0, conn, NULL);
+	async_connect_to_me(exch, 0, 0, 0, vfs_connection, NULL);
 	
 	/*
 	 * Allocate piece of address space for PLB.
 	 */
-	reg->plb_ro = as_get_mappable_page(PLB_SIZE);
-	if (!reg->plb_ro) {
+	reg.plb_ro = as_get_mappable_page(PLB_SIZE);
+	if (!reg.plb_ro) {
 		async_exchange_end(exch);
 		async_wait_for(req, NULL);
@@ -121,5 +348,5 @@
 	 * Request sharing the Path Lookup Buffer with VFS.
 	 */
-	rc = async_share_in_start_0_0(exch, reg->plb_ro, PLB_SIZE);
+	rc = async_share_in_start_0_0(exch, reg.plb_ro, PLB_SIZE);
 	
 	async_exchange_end(exch);
@@ -134,5 +361,5 @@
 	 */
 	async_wait_for(req, NULL);
-	reg->fs_handle = (int) IPC_GET_ARG1(answer);
+	reg.fs_handle = (int) IPC_GET_ARG1(answer);
 	
 	/*
@@ -140,5 +367,5 @@
 	 * the same connection fibril as well.
 	 */
-	async_set_client_connection(conn);
+	async_set_client_connection(vfs_connection);
 	
 	return IPC_GET_RETVAL(answer);
@@ -151,10 +378,10 @@
 
 void libfs_mount(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
-    ipc_call_t *request)
-{
-	devmap_handle_t mp_devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-	fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*request);
-	fs_handle_t mr_fs_handle = (fs_handle_t) IPC_GET_ARG3(*request);
-	devmap_handle_t mr_devmap_handle = (devmap_handle_t) IPC_GET_ARG4(*request);
+    ipc_call_t *req)
+{
+	devmap_handle_t mp_devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req);
+	fs_handle_t mr_fs_handle = (fs_handle_t) IPC_GET_ARG3(*req);
+	devmap_handle_t mr_devmap_handle = (devmap_handle_t) IPC_GET_ARG4(*req);
 	
 	async_sess_t *mountee_sess = async_clone_receive(EXCHANGE_PARALLEL);
@@ -208,12 +435,12 @@
 	 * Do not release the FS node so that it stays in memory.
 	 */
-	async_answer_3(rid, rc, IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
-	    IPC_GET_ARG3(answer));
-}
-
-void libfs_unmount(libfs_ops_t *ops, ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t mp_devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-	fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*request);
+	async_answer_4(rid, rc, IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
+	    IPC_GET_ARG3(answer), IPC_GET_ARG4(answer));
+}
+
+void libfs_unmount(libfs_ops_t *ops, ipc_callid_t rid, ipc_call_t *req)
+{
+	devmap_handle_t mp_devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req);
 	fs_node_t *fn;
 	int res;
@@ -259,4 +486,9 @@
 }
 
+static char plb_get_char(unsigned pos)
+{
+	return reg.plb_ro[pos % PLB_SIZE];
+}
+
 /** Lookup VFS triplet by name in the file system name space.
  *
@@ -273,12 +505,12 @@
  */
 void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
-    ipc_call_t *request)
-{
-	unsigned int first = IPC_GET_ARG1(*request);
-	unsigned int last = IPC_GET_ARG2(*request);
+    ipc_call_t *req)
+{
+	unsigned int first = IPC_GET_ARG1(*req);
+	unsigned int last = IPC_GET_ARG2(*req);
 	unsigned int next = first;
-	devmap_handle_t devmap_handle = IPC_GET_ARG3(*request);
-	int lflag = IPC_GET_ARG4(*request);
-	fs_index_t index = IPC_GET_ARG5(*request);
+	devmap_handle_t devmap_handle = IPC_GET_ARG3(*req);
+	int lflag = IPC_GET_ARG4(*req);
+	fs_index_t index = IPC_GET_ARG5(*req);
 	char component[NAME_MAX + 1];
 	int len;
@@ -298,5 +530,6 @@
 		async_exch_t *exch = async_exchange_begin(cur->mp_data.sess);
 		async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last,
-		    cur->mp_data.devmap_handle, lflag, index, IPC_FF_ROUTE_FROM_ME);
+		    cur->mp_data.devmap_handle, lflag, index,
+		    IPC_FF_ROUTE_FROM_ME);
 		async_exchange_end(exch);
 		
@@ -306,5 +539,5 @@
 	
 	/* Eat slash */
-	if (ops->plb_get_char(next) == '/')
+	if (plb_get_char(next) == '/')
 		next++;
 	
@@ -319,5 +552,5 @@
 		/* Collect the component */
 		len = 0;
-		while ((next <= last) && (ops->plb_get_char(next) != '/')) {
+		while ((next <= last) && (plb_get_char(next) != '/')) {
 			if (len + 1 == NAME_MAX) {
 				/* Component length overflow */
@@ -325,5 +558,5 @@
 				goto out;
 			}
-			component[len++] = ops->plb_get_char(next);
+			component[len++] = plb_get_char(next);
 			/* Process next character */
 			next++;
@@ -357,6 +590,6 @@
 			
 			async_exch_t *exch = async_exchange_begin(tmp->mp_data.sess);
-			async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last,
-			    tmp->mp_data.devmap_handle, lflag, index,
+			async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next,
+			    last, tmp->mp_data.devmap_handle, lflag, index,
 			    IPC_FF_ROUTE_FROM_ME);
 			async_exchange_end(exch);
@@ -451,5 +684,5 @@
 			len = 0;
 			while (next <= last) {
-				if (ops->plb_get_char(next) == '/') {
+				if (plb_get_char(next) == '/') {
 					/* More than one component */
 					async_answer_0(rid, ENOENT);
@@ -463,5 +696,5 @@
 				}
 				
-				component[len++] = ops->plb_get_char(next);
+				component[len++] = plb_get_char(next);
 				/* Process next character */
 				next++;
@@ -637,5 +870,6 @@
 	rc = ops->node_open(fn);
 	aoff64_t size = ops->size_get(fn);
-	async_answer_4(rid, rc, LOWER32(size), UPPER32(size), ops->lnkcnt_get(fn),
+	async_answer_4(rid, rc, LOWER32(size), UPPER32(size),
+	    ops->lnkcnt_get(fn),
 	    (ops->is_file(fn) ? L_FILE : 0) | (ops->is_directory(fn) ? L_DIRECTORY : 0));
 	
Index: uspace/lib/fs/libfs.h
===================================================================
--- uspace/lib/fs/libfs.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/fs/libfs.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -43,4 +43,17 @@
 
 typedef struct {
+	int (* mounted)(devmap_handle_t, const char *, fs_index_t *, aoff64_t *,
+	    unsigned *);
+	int (* unmounted)(devmap_handle_t);
+	int (* read)(devmap_handle_t, fs_index_t, aoff64_t, size_t *);
+	int (* write)(devmap_handle_t, fs_index_t, aoff64_t, size_t *,
+	    aoff64_t *);
+	int (* truncate)(devmap_handle_t, fs_index_t, aoff64_t);
+	int (* close)(devmap_handle_t, fs_index_t);
+	int (* destroy)(devmap_handle_t, fs_index_t);
+	int (* sync)(devmap_handle_t, fs_index_t);
+} vfs_out_ops_t;
+
+typedef struct {
 	bool mp_active;
 	async_sess_t *sess;
@@ -71,11 +84,10 @@
 	int (* has_children)(bool *, fs_node_t *);
 	/*
-	 * The second set of methods are usually mere getters that do not return
-	 * an integer error code.
+	 * The second set of methods are usually mere getters that do not
+	 * return an integer error code.
 	 */
 	fs_index_t (* index_get)(fs_node_t *);
 	aoff64_t (* size_get)(fs_node_t *);
 	unsigned int (* lnkcnt_get)(fs_node_t *);
-	char (* plb_get_char)(unsigned pos);
 	bool (* is_directory)(fs_node_t *);
 	bool (* is_file)(fs_node_t *);
@@ -88,15 +100,8 @@
 } fs_reg_t;
 
-extern int fs_register(async_sess_t *, fs_reg_t *, vfs_info_t *,
-    async_client_conn_t);
+extern int fs_register(async_sess_t *, vfs_info_t *, vfs_out_ops_t *,
+    libfs_ops_t *);
 
 extern void fs_node_initialize(fs_node_t *);
-
-extern void libfs_mount(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
-extern void libfs_unmount(libfs_ops_t *, ipc_callid_t, ipc_call_t *);
-extern void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
-extern void libfs_stat(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
-extern void libfs_open_node(libfs_ops_t *, fs_handle_t, ipc_callid_t,
-    ipc_call_t *);
 
 #endif
Index: uspace/lib/scsi/include/scsi/sbc.h
===================================================================
--- uspace/lib/scsi/include/scsi/sbc.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/scsi/include/scsi/sbc.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -56,9 +56,25 @@
 };
 
+/** SCSI Read (10) command */
+typedef struct {
+	/** Operation code (SCSI_CMD_READ_10) */
+	uint8_t op_code;
+	/** RdProtect, DPO, FUA, Reserved, FUA_NV, Obsolete */
+	uint8_t flags;
+	/** Logical block address */
+	uint32_t lba;
+	/** Reserved, Group Number */
+	uint8_t group_no;
+	/** Transfer length */
+	uint16_t xfer_len;
+	/** Control */
+	uint8_t control;
+} __attribute__((packed)) scsi_cdb_read_10_t;
+
 /** SCSI Read (12) command */
 typedef struct {
 	/** Operation code (SCSI_CMD_READ_12) */
 	uint8_t op_code;
-	/** RdProtect, DPO, FUA, Reserved, FUA_NV, Reserved */
+	/** RdProtect, DPO, FUA, Reserved, FUA_NV, Obsolete */
 	uint8_t flags;
 	/** Logical block address */
@@ -115,9 +131,25 @@
 } scsi_read_capacity_10_data_t;
 
+/** SCSI Write (10) command */
+typedef struct {
+	/** Operation code (SCSI_CMD_WRITE_10) */
+	uint8_t op_code;
+	/** WrProtect, DPO, FUA, Reserved, FUA_NV, Obsolete */
+	uint8_t flags;
+	/** Logical block address */
+	uint32_t lba;
+	/** Reserved, Group Number */
+	uint8_t group_no;
+	/** Transfer length */
+	uint16_t xfer_len;
+	/** Control */
+	uint8_t control;
+} __attribute__((packed)) scsi_cdb_write_10_t;
+
 /** SCSI Write (12) command */
 typedef struct {
 	/** Operation code (SCSI_CMD_WRITE_12) */
 	uint8_t op_code;
-	/** WrProtect, DPO, FUA, Reserved, FUA_NV, Reserved */
+	/** WrProtect, DPO, FUA, Reserved, FUA_NV, Obsolete */
 	uint8_t flags;
 	/** Logical block address */
Index: uspace/lib/scsi/include/scsi/spc.h
===================================================================
--- uspace/lib/scsi/include/scsi/spc.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/scsi/include/scsi/spc.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -179,5 +179,5 @@
 	uint8_t additional_len;
 	/** Command-specific Information */
-	uint8_t cmd_spec;
+	uint32_t cmd_spec;
 	/** Additional Sense Code */
 	uint8_t additional_code;
@@ -205,9 +205,14 @@
 	SCSI_SK_ABORTED_COMMAND	= 0xb,
 	SCSI_SK_VOLUME_OVERFLOW	= 0xd,
-	SCSI_SK_MISCOMPARE	= 0xe
+	SCSI_SK_MISCOMPARE	= 0xe,
+
+	SCSI_SK_LIMIT		= 0x10
 };
 
 extern const char *scsi_dev_type_str[SCSI_DEV_LIMIT];
+extern const char *scsi_sense_key_str[SCSI_SK_LIMIT];
+
 extern const char *scsi_get_dev_type_str(unsigned);
+extern const char *scsi_get_sense_key_str(unsigned);
 
 #endif
Index: uspace/lib/scsi/src/spc.c
===================================================================
--- uspace/lib/scsi/src/spc.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/lib/scsi/src/spc.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -44,4 +44,21 @@
 };
 
+const char *scsi_sense_key_str[SCSI_SK_LIMIT] = {
+	[SCSI_SK_NO_SENSE]		= "No Sense",
+	[SCSI_SK_RECOVERED_ERROR]	= "Recovered Error",
+	[SCSI_SK_NOT_READY]		= "Not Ready",
+	[SCSI_SK_MEDIUM_ERROR]		= "Medium Error",
+	[SCSI_SK_HARDWARE_ERROR]	= "Hardware Error",
+	[SCSI_SK_ILLEGAL_REQUEST]	= "Illegal Request",
+	[SCSI_SK_UNIT_ATTENTION]	= "Unit Attention",
+	[SCSI_SK_DATA_PROTECT]		= "Data Protect",
+	[SCSI_SK_BLANK_CHECK]		= "Blank Check",
+	[SCSI_SK_VENDOR_SPECIFIC]	= "Vendor-specific",
+	[SCSI_SK_COPY_ABORTED]		= "Copy Aborted",
+	[SCSI_SK_ABORTED_COMMAND]	= "Aborted Command",
+	[SCSI_SK_VOLUME_OVERFLOW]	= "Volume Overflow",
+	[SCSI_SK_MISCOMPARE]		= "Miscompare"
+};
+
 /** Get peripheral device type string.
  *
@@ -53,6 +70,21 @@
 {
 	if (dev_type >= SCSI_DEV_LIMIT || scsi_dev_type_str[dev_type] == NULL)
-		return "<unknown>";
+		return "Unknown";
 
 	return scsi_dev_type_str[dev_type];
 }
+
+/** Get sense key string.
+ *
+ * Return string description of SCSI sense key.
+ * The returned string is valid indefinitely, the caller should
+ * not attempt to free it.
+ */
+const char *scsi_get_sense_key_str(unsigned sense_key)
+{
+	if (sense_key >= SCSI_SK_LIMIT || scsi_sense_key_str[sense_key] == NULL)
+		return "Unknown";
+
+	return scsi_sense_key_str[sense_key];
+}
+
Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/devman/devman.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -270,7 +270,8 @@
 	}
 	
-	ssize_t read_bytes = safe_read(fd, buf, len);
+	ssize_t read_bytes = read_all(fd, buf, len);
 	if (read_bytes <= 0) {
-		log_msg(LVL_ERROR, "Unable to read file '%s'.", conf_path);
+		log_msg(LVL_ERROR, "Unable to read file '%s' (%zd).", conf_path,
+		    read_bytes);
 		goto cleanup;
 	}
@@ -421,7 +422,7 @@
 	}
 	
-	insert_fun_node(tree, fun, clone_string(""), NULL);
+	insert_fun_node(tree, fun, str_dup(""), NULL);
 	match_id_t *id = create_match_id();
-	id->id = clone_string("root");
+	id->id = str_dup("root");
 	id->score = 100;
 	add_match_id(&fun->match_ids, id);
Index: uspace/srv/devman/util.c
===================================================================
--- uspace/srv/devman/util.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/devman/util.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -91,15 +91,4 @@
 }
 
-char *clone_string(const char *s)
-{
-	size_t size = str_size(s) + 1;
-	char *str;
-	
-	str = (char *) malloc(size);
-	if (str != NULL)
-		str_cpy(str, size, s);
-	return str;
-}
-
 void replace_char(char *str, char orig, char repl)
 {
@@ -111,31 +100,4 @@
 }
 
-ssize_t safe_read(int fd, void *buffer, size_t size)
-{
-	if (size == 0) {
-		return 0;
-	}
-
-	uint8_t *buf_ptr = (uint8_t *) buffer;
-
-	size_t total_read = 0;
-	while (total_read < size) {
-		ssize_t bytes_read = read(fd, buf_ptr, size - total_read);
-		if (bytes_read < 0) {
-			/* Error. */
-			return bytes_read;
-		} else if (bytes_read == 0) {
-			/* Possibly end of file. */
-			break;
-		} else {
-			/* Read at least something. */
-			buf_ptr += bytes_read;
-			total_read += bytes_read;
-		}
-	}
-
-	return (ssize_t) total_read;
-}
-
 /** @}
  */
Index: uspace/srv/devman/util.h
===================================================================
--- uspace/srv/devman/util.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/devman/util.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -44,8 +44,5 @@
 extern size_t get_nonspace_len(const char *);
 extern void free_not_null(const void *);
-extern char *clone_string(const char *);
 extern void replace_char(char *, char, char);
-
-extern ssize_t safe_read(int, void *, size_t);
 
 #endif
Index: uspace/srv/fs/devfs/devfs.c
===================================================================
--- uspace/srv/fs/devfs/devfs.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/fs/devfs/devfs.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -57,65 +57,4 @@
 };
 
-fs_reg_t devfs_reg;
-
-static void devfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	if (iid)
-		async_answer_0(iid, EOK);
-	
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call))
-			return;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case VFS_OUT_MOUNTED:
-			devfs_mounted(callid, &call);
-			break;
-		case VFS_OUT_MOUNT:
-			devfs_mount(callid, &call);
-			break;
-		case VFS_OUT_UNMOUNTED:
-			devfs_unmounted(callid, &call);
-			break;
-		case VFS_OUT_UNMOUNT:
-			devfs_unmount(callid, &call);
-			break;
-		case VFS_OUT_LOOKUP:
-			devfs_lookup(callid, &call);
-			break;
-		case VFS_OUT_OPEN_NODE:
-			devfs_open_node(callid, &call);
-			break;
-		case VFS_OUT_STAT:
-			devfs_stat(callid, &call);
-			break;
-		case VFS_OUT_READ:
-			devfs_read(callid, &call);
-			break;
-		case VFS_OUT_WRITE:
-			devfs_write(callid, &call);
-			break;
-		case VFS_OUT_TRUNCATE:
-			devfs_truncate(callid, &call);
-			break;
-		case VFS_OUT_CLOSE:
-			devfs_close(callid, &call);
-			break;
-		case VFS_OUT_SYNC:
-			devfs_sync(callid, &call);
-			break;
-		case VFS_OUT_DESTROY:
-			devfs_destroy(callid, &call);
-			break;
-		default:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		}
-	}
-}
-
 int main(int argc, char *argv[])
 {
@@ -134,6 +73,6 @@
 	}
 	
-	int rc = fs_register(vfs_sess, &devfs_reg, &devfs_vfs_info,
-	    devfs_connection);
+	int rc = fs_register(vfs_sess, &devfs_vfs_info, &devfs_ops,
+	    &devfs_libfs_ops);
 	if (rc != EOK) {
 		printf("%s: Failed to register file system (%d)\n", NAME, rc);
@@ -152,2 +91,3 @@
  * @}
  */
+
Index: uspace/srv/fs/devfs/devfs.h
===================================================================
--- uspace/srv/fs/devfs/devfs.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/fs/devfs/devfs.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -36,5 +36,6 @@
 #include <libfs.h>
 
-extern fs_reg_t devfs_reg;
+extern vfs_out_ops_t devfs_ops;
+extern libfs_ops_t devfs_libfs_ops;
 
 #endif
Index: uspace/srv/fs/devfs/devfs_ops.c
===================================================================
--- uspace/srv/fs/devfs/devfs_ops.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/fs/devfs/devfs_ops.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -403,9 +403,4 @@
 }
 
-static char devfs_plb_get_char(unsigned pos)
-{
-	return devfs_reg.plb_ro[pos % PLB_SIZE];
-}
-
 static bool devfs_is_directory(fs_node_t *fn)
 {
@@ -447,5 +442,4 @@
 	.size_get = devfs_size_get,
 	.lnkcnt_get = devfs_lnkcnt_get,
-	.plb_get_char = devfs_plb_get_char,
 	.is_directory = devfs_is_directory,
 	.is_file = devfs_is_file,
@@ -462,56 +456,22 @@
 }
 
-void devfs_mounted(ipc_callid_t rid, ipc_call_t *request)
-{
-	char *opts;
-	
-	/* Accept the mount options */
-	sysarg_t retval = async_data_write_accept((void **) &opts, true, 0, 0,
-	    0, NULL);
-	if (retval != EOK) {
-		async_answer_0(rid, retval);
-		return;
-	}
-	
-	free(opts);
-	async_answer_3(rid, EOK, 0, 0, 0);
-}
-
-void devfs_mount(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_mount(&devfs_libfs_ops, devfs_reg.fs_handle, rid, request);
-}
-
-void devfs_unmounted(ipc_callid_t rid, ipc_call_t *request)
-{
-	async_answer_0(rid, ENOTSUP);
-}
-
-void devfs_unmount(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_unmount(&devfs_libfs_ops, rid, request);
-}
-
-void devfs_lookup(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_lookup(&devfs_libfs_ops, devfs_reg.fs_handle, rid, request);
-}
-
-void devfs_open_node(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_open_node(&devfs_libfs_ops, devfs_reg.fs_handle, rid, request);
-}
-
-void devfs_stat(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_stat(&devfs_libfs_ops, devfs_reg.fs_handle, rid, request);
-}
-
-void devfs_read(ipc_callid_t rid, ipc_call_t *request)
-{
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	aoff64_t pos =
-	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
-	
+static int devfs_mounted(devmap_handle_t devmap_handle, const char *opts,
+    fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
+{
+	*index = 0;
+	*size = 0;
+	*lnkcnt = 0;
+	return EOK;
+}
+
+static int devfs_unmounted(devmap_handle_t devmap_handle)
+{
+	return ENOTSUP;
+}
+
+static int
+devfs_read(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+    size_t *rbytes)
+{
 	if (index == 0) {
 		ipc_callid_t callid;
@@ -519,6 +479,5 @@
 		if (!async_data_read_receive(&callid, &size)) {
 			async_answer_0(callid, EINVAL);
-			async_answer_0(rid, EINVAL);
-			return;
+			return EINVAL;
 		}
 		
@@ -540,6 +499,6 @@
 			async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
 			free(desc);
-			async_answer_1(rid, EOK, 1);
-			return;
+			*rbytes = 1;
+			return EOK;
 		}
 		
@@ -555,6 +514,6 @@
 				async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
 				free(desc);
-				async_answer_1(rid, EOK, 1);
-				return;
+				*rbytes = 1;
+				return EOK;
 			}
 			
@@ -563,6 +522,5 @@
 		
 		async_answer_0(callid, ENOENT);
-		async_answer_1(rid, ENOENT, 0);
-		return;
+		return ENOENT;
 	}
 	
@@ -575,6 +533,5 @@
 		if (!async_data_read_receive(&callid, &size)) {
 			async_answer_0(callid, EINVAL);
-			async_answer_0(rid, EINVAL);
-			return;
+			return EINVAL;
 		}
 		
@@ -585,12 +542,11 @@
 			async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
 			free(desc);
-			async_answer_1(rid, EOK, 1);
-			return;
+			*rbytes = 1;
+			return EOK;
 		}
 		
 		free(desc);
 		async_answer_0(callid, ENOENT);
-		async_answer_1(rid, ENOENT, 0);
-		return;
+		return ENOENT;
 	}
 	
@@ -606,6 +562,5 @@
 		if (lnk == NULL) {
 			fibril_mutex_unlock(&devices_mutex);
-			async_answer_0(rid, ENOENT);
-			return;
+			return ENOENT;
 		}
 		
@@ -617,6 +572,5 @@
 			fibril_mutex_unlock(&devices_mutex);
 			async_answer_0(callid, EINVAL);
-			async_answer_0(rid, EINVAL);
-			return;
+			return EINVAL;
 		}
 		
@@ -625,7 +579,6 @@
 		
 		ipc_call_t answer;
-		aid_t msg = async_send_3(exch, IPC_GET_IMETHOD(*request),
-		    IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
-		    IPC_GET_ARG3(*request), &answer);
+		aid_t msg = async_send_4(exch, VFS_OUT_READ, devmap_handle,
+		    index, LOWER32(pos), UPPER32(pos), &answer);
 		
 		/* Forward the IPC_M_DATA_READ request to the driver */
@@ -639,21 +592,18 @@
 		sysarg_t rc;
 		async_wait_for(msg, &rc);
-		size_t bytes = IPC_GET_ARG1(answer);
-		
-		/* Driver reply is the final result of the whole operation */
-		async_answer_1(rid, rc, bytes);
-		return;
-	}
-	
-	async_answer_0(rid, ENOENT);
-}
-
-void devfs_write(ipc_callid_t rid, ipc_call_t *request)
-{
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	if (index == 0) {
-		async_answer_0(rid, ENOTSUP);
-		return;
-	}
+		
+		*rbytes = IPC_GET_ARG1(answer);
+		return rc;
+	}
+	
+	return ENOENT;
+}
+
+static int
+devfs_write(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+    size_t *wbytes, aoff64_t *nsize)
+{
+	if (index == 0)
+		return ENOTSUP;
 	
 	devmap_handle_type_t type = devmap_handle_probe(index);
@@ -661,6 +611,5 @@
 	if (type == DEV_HANDLE_NAMESPACE) {
 		/* Namespace directory */
-		async_answer_0(rid, ENOTSUP);
-		return;
+		return ENOTSUP;
 	}
 	
@@ -675,6 +624,5 @@
 		if (lnk == NULL) {
 			fibril_mutex_unlock(&devices_mutex);
-			async_answer_0(rid, ENOENT);
-			return;
+			return ENOENT;
 		}
 		
@@ -686,6 +634,5 @@
 			fibril_mutex_unlock(&devices_mutex);
 			async_answer_0(callid, EINVAL);
-			async_answer_0(rid, EINVAL);
-			return;
+			return EINVAL;
 		}
 		
@@ -694,7 +641,6 @@
 		
 		ipc_call_t answer;
-		aid_t msg = async_send_3(exch, IPC_GET_IMETHOD(*request),
-		    IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
-		    IPC_GET_ARG3(*request), &answer);
+		aid_t msg = async_send_4(exch, VFS_OUT_WRITE, devmap_handle,
+		    index, LOWER32(pos), UPPER32(pos), &answer);
 		
 		/* Forward the IPC_M_DATA_WRITE request to the driver */
@@ -708,27 +654,23 @@
 		sysarg_t rc;
 		async_wait_for(msg, &rc);
-		size_t bytes = IPC_GET_ARG1(answer);
-		
-		/* Driver reply is the final result of the whole operation */
-		async_answer_1(rid, rc, bytes);
-		return;
-	}
-	
-	async_answer_0(rid, ENOENT);
-}
-
-void devfs_truncate(ipc_callid_t rid, ipc_call_t *request)
-{
-	async_answer_0(rid, ENOTSUP);
-}
-
-void devfs_close(ipc_callid_t rid, ipc_call_t *request)
-{
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	
-	if (index == 0) {
-		async_answer_0(rid, EOK);
-		return;
-	}
+		
+		*wbytes = IPC_GET_ARG1(answer);
+		*nsize = 0;
+		return rc;
+	}
+	
+	return ENOENT;
+}
+
+static int
+devfs_truncate(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t size)
+{
+	return ENOTSUP;
+}
+
+static int devfs_close(devmap_handle_t devmap_handle, fs_index_t index)
+{
+	if (index == 0)
+		return EOK;
 	
 	devmap_handle_type_t type = devmap_handle_probe(index);
@@ -736,6 +678,5 @@
 	if (type == DEV_HANDLE_NAMESPACE) {
 		/* Namespace directory */
-		async_answer_0(rid, EOK);
-		return;
+		return EOK;
 	}
 	
@@ -749,6 +690,5 @@
 		if (lnk == NULL) {
 			fibril_mutex_unlock(&devices_mutex);
-			async_answer_0(rid, ENOENT);
-			return;
+			return ENOENT;
 		}
 		
@@ -764,19 +704,14 @@
 		fibril_mutex_unlock(&devices_mutex);
 		
-		async_answer_0(rid, EOK);
-		return;
-	}
-	
-	async_answer_0(rid, ENOENT);
-}
-
-void devfs_sync(ipc_callid_t rid, ipc_call_t *request)
-{
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	
-	if (index == 0) {
-		async_answer_0(rid, EOK);
-		return;
-	}
+		return EOK;
+	}
+	
+	return ENOENT;
+}
+
+static int devfs_sync(devmap_handle_t devmap_handle, fs_index_t index)
+{
+	if (index == 0)
+		return EOK;
 	
 	devmap_handle_type_t type = devmap_handle_probe(index);
@@ -784,6 +719,5 @@
 	if (type == DEV_HANDLE_NAMESPACE) {
 		/* Namespace directory */
-		async_answer_0(rid, EOK);
-		return;
+		return EOK;
 	}
 	
@@ -797,6 +731,5 @@
 		if (lnk == NULL) {
 			fibril_mutex_unlock(&devices_mutex);
-			async_answer_0(rid, ENOENT);
-			return;
+			return ENOENT;
 		}
 		
@@ -808,6 +741,6 @@
 		
 		ipc_call_t answer;
-		aid_t msg = async_send_2(exch, IPC_GET_IMETHOD(*request),
-		    IPC_GET_ARG1(*request), IPC_GET_ARG2(*request), &answer);
+		aid_t msg = async_send_2(exch, VFS_OUT_SYNC, devmap_handle,
+		    index, &answer);
 		
 		async_exchange_end(exch);
@@ -819,16 +752,25 @@
 		async_wait_for(msg, &rc);
 		
-		/* Driver reply is the final result of the whole operation */
-		async_answer_0(rid, rc);
-		return;
-	}
-	
-	async_answer_0(rid, ENOENT);
-}
-
-void devfs_destroy(ipc_callid_t rid, ipc_call_t *request)
-{
-	async_answer_0(rid, ENOTSUP);
-}
+		return rc;
+	}
+	
+	return  ENOENT;
+}
+
+static int devfs_destroy(devmap_handle_t devmap_handle, fs_index_t index)
+{
+	return ENOTSUP;
+}
+
+vfs_out_ops_t devfs_ops = {
+	.mounted = devfs_mounted,
+	.unmounted = devfs_unmounted,
+	.read = devfs_read,
+	.write = devfs_write,
+	.truncate = devfs_truncate,
+	.close = devfs_close,
+	.destroy = devfs_destroy,
+	.sync = devfs_sync,
+};
 
 /**
Index: uspace/srv/fs/devfs/devfs_ops.h
===================================================================
--- uspace/srv/fs/devfs/devfs_ops.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/fs/devfs/devfs_ops.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -34,22 +34,7 @@
 #define DEVFS_DEVFS_OPS_H_
 
-#include <ipc/common.h>
 #include <bool.h>
 
 extern bool devfs_init(void);
-
-extern void devfs_mounted(ipc_callid_t, ipc_call_t *);
-extern void devfs_mount(ipc_callid_t, ipc_call_t *);
-extern void devfs_unmounted(ipc_callid_t, ipc_call_t *);
-extern void devfs_unmount(ipc_callid_t, ipc_call_t *);
-extern void devfs_lookup(ipc_callid_t, ipc_call_t *);
-extern void devfs_open_node(ipc_callid_t, ipc_call_t *);
-extern void devfs_stat(ipc_callid_t, ipc_call_t *);
-extern void devfs_sync(ipc_callid_t, ipc_call_t *);
-extern void devfs_read(ipc_callid_t, ipc_call_t *);
-extern void devfs_write(ipc_callid_t, ipc_call_t *);
-extern void devfs_truncate(ipc_callid_t, ipc_call_t *);
-extern void devfs_close(ipc_callid_t, ipc_call_t *);
-extern void devfs_destroy(ipc_callid_t, ipc_call_t *);
 
 #endif
Index: uspace/srv/fs/ext2fs/ext2fs.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/fs/ext2fs/ext2fs.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -1,5 +1,4 @@
 /*
  * Copyright (c) 2006 Martin Decky
- * Copyright (c) 2008 Jakub Jermar
  * Copyright (c) 2011 Martin Sucha
  * All rights reserved.
@@ -55,90 +54,4 @@
 };
 
-fs_reg_t ext2fs_reg;
-
-/**
- * This connection fibril processes VFS requests from VFS.
- *
- * In order to support simultaneous VFS requests, our design is as follows.
- * The connection fibril accepts VFS requests from VFS. If there is only one
- * instance of the fibril, VFS will need to serialize all VFS requests it sends
- * to EXT2FS. To overcome this bottleneck, VFS can send EXT2FS the IPC_M_CONNECT_ME_TO
- * call. In that case, a new connection fibril will be created, which in turn
- * will accept the call. Thus, a new phone will be opened for VFS.
- *
- * There are few issues with this arrangement. First, VFS can run out of
- * available phones. In that case, VFS can close some other phones or use one
- * phone for more serialized requests. Similarily, EXT2FS can refuse to duplicate
- * the connection. VFS should then just make use of already existing phones and
- * route its requests through them. To avoid paying the fibril creation price 
- * upon each request, EXT2FS might want to keep the connections open after the
- * request has been completed.
- */
-static void ext2fs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	if (iid) {
-		/*
-		 * This only happens for connections opened by
-		 * IPC_M_CONNECT_ME_TO calls as opposed to callback connections
-		 * created by IPC_M_CONNECT_TO_ME.
-		 */
-		async_answer_0(iid, EOK);
-	}
-	
-	dprintf(NAME ": connection opened\n");
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call))
-			return;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case VFS_OUT_MOUNTED:
-			ext2fs_mounted(callid, &call);
-			break;
-		case VFS_OUT_MOUNT:
-			ext2fs_mount(callid, &call);
-			break;
-		case VFS_OUT_UNMOUNTED:
-			ext2fs_unmounted(callid, &call);
-			break;
-		case VFS_OUT_UNMOUNT:
-			ext2fs_unmount(callid, &call);
-			break;
-		case VFS_OUT_LOOKUP:
-			ext2fs_lookup(callid, &call);
-			break;
-		case VFS_OUT_READ:
-			ext2fs_read(callid, &call);
-			break;
-		case VFS_OUT_WRITE:
-			ext2fs_write(callid, &call);
-			break;
-		case VFS_OUT_TRUNCATE:
-			ext2fs_truncate(callid, &call);
-			break;
-		case VFS_OUT_STAT:
-			ext2fs_stat(callid, &call);
-			break;
-		case VFS_OUT_CLOSE:
-			ext2fs_close(callid, &call);
-			break;
-		case VFS_OUT_DESTROY:
-			ext2fs_destroy(callid, &call);
-			break;
-		case VFS_OUT_OPEN_NODE:
-			ext2fs_open_node(callid, &call);
-			break;
-		case VFS_OUT_SYNC:
-			ext2fs_sync(callid, &call);
-			break;
-		default:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		}
-	}
-}
-
 int main(int argc, char **argv)
 {
@@ -158,5 +71,6 @@
 	}	
 		
-	rc = fs_register(vfs_sess, &ext2fs_reg, &ext2fs_vfs_info, ext2fs_connection);
+	rc = fs_register(vfs_sess, &ext2fs_vfs_info, &ext2fs_ops,
+	    &ext2fs_libfs_ops);
 	if (rc != EOK) {
 		fprintf(stdout, NAME ": Failed to register fs (%d)\n", rc);
Index: uspace/srv/fs/ext2fs/ext2fs.h
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/fs/ext2fs/ext2fs.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -1,4 +1,3 @@
 /*
- * Copyright (c) 2008 Jakub Jermar
  * Copyright (c) 2011 Martin Sucha
  * All rights reserved.
@@ -36,35 +35,14 @@
 
 #include <libext2.h>
-#include <fibril_synch.h>
 #include <libfs.h>
-#include <atomic.h>
 #include <sys/types.h>
-#include <bool.h>
-#include "../../vfs/vfs.h"
-
-#ifndef dprintf
-#define dprintf(...)	printf(__VA_ARGS__)
-#endif
 
 #define min(a, b)		((a) < (b) ? (a) : (b))
 
-extern fs_reg_t ext2fs_reg;
+extern vfs_out_ops_t ext2fs_ops;
+extern libfs_ops_t ext2fs_libfs_ops;
 
 extern int ext2fs_global_init(void);
 extern int ext2fs_global_fini(void);
-extern void ext2fs_mounted(ipc_callid_t, ipc_call_t *);
-extern void ext2fs_mount(ipc_callid_t, ipc_call_t *);
-extern void ext2fs_unmounted(ipc_callid_t, ipc_call_t *);
-extern void ext2fs_unmount(ipc_callid_t, ipc_call_t *);
-extern void ext2fs_lookup(ipc_callid_t, ipc_call_t *);
-extern void ext2fs_read(ipc_callid_t, ipc_call_t *);
-extern void ext2fs_write(ipc_callid_t, ipc_call_t *);
-extern void ext2fs_truncate(ipc_callid_t, ipc_call_t *);
-extern void ext2fs_stat(ipc_callid_t, ipc_call_t *);
-extern void ext2fs_close(ipc_callid_t, ipc_call_t *);
-extern void ext2fs_destroy(ipc_callid_t, ipc_call_t *);
-extern void ext2fs_open_node(ipc_callid_t, ipc_call_t *);
-extern void ext2fs_stat(ipc_callid_t, ipc_call_t *);
-extern void ext2fs_sync(ipc_callid_t, ipc_call_t *);
 
 #endif
Index: uspace/srv/fs/ext2fs/ext2fs_ops.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -1,4 +1,3 @@
 /*
- * Copyright (c) 2008 Jakub Jermar
  * Copyright (c) 2011 Martin Sucha
  * All rights reserved.
@@ -87,8 +86,8 @@
  */
 static int ext2fs_instance_get(devmap_handle_t, ext2fs_instance_t **);
-static void ext2fs_read_directory(ipc_callid_t, ipc_callid_t, aoff64_t,
-	size_t, ext2fs_instance_t *, ext2_inode_ref_t *);
-static void ext2fs_read_file(ipc_callid_t, ipc_callid_t, aoff64_t,
-	size_t, ext2fs_instance_t *, ext2_inode_ref_t *);
+static int ext2fs_read_directory(ipc_callid_t, aoff64_t, size_t,
+    ext2fs_instance_t *, ext2_inode_ref_t *, size_t *);
+static int ext2fs_read_file(ipc_callid_t, aoff64_t, size_t, ext2fs_instance_t *,
+    ext2_inode_ref_t *, size_t *);
 static bool ext2fs_is_dots(const uint8_t *, size_t);
 static int ext2fs_node_get_core(fs_node_t **, ext2fs_instance_t *, fs_index_t);
@@ -111,5 +110,4 @@
 static aoff64_t ext2fs_size_get(fs_node_t *);
 static unsigned ext2fs_lnkcnt_get(fs_node_t *);
-static char ext2fs_plb_get_char(unsigned);
 static bool ext2fs_is_directory(fs_node_t *);
 static bool ext2fs_is_file(fs_node_t *node);
@@ -538,9 +536,4 @@
 	EXT2FS_DBG("%u", count);
 	return count;
-}
-
-char ext2fs_plb_get_char(unsigned pos)
-{
-	return ext2fs_reg.plb_ro[pos % PLB_SIZE];
 }
 
@@ -586,5 +579,4 @@
 	.size_get = ext2fs_size_get,
 	.lnkcnt_get = ext2fs_lnkcnt_get,
-	.plb_get_char = ext2fs_plb_get_char,
 	.is_directory = ext2fs_is_directory,
 	.is_file = ext2fs_is_file,
@@ -596,30 +588,17 @@
  */
 
-void ext2fs_mounted(ipc_callid_t rid, ipc_call_t *request)
-{
-	EXT2FS_DBG("");
-	int rc;
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+static int ext2fs_mounted(devmap_handle_t devmap_handle, const char *opts,
+   fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
+{
+	EXT2FS_DBG("");
+	int rc;
 	ext2_filesystem_t *fs;
 	ext2fs_instance_t *inst;
 	bool read_only;
 	
-	/* Accept the mount options */
-	char *opts;
-	rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
-	
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-
-	free(opts);
-	
 	/* Allocate libext2 filesystem structure */
 	fs = (ext2_filesystem_t *) malloc(sizeof(ext2_filesystem_t));
-	if (fs == NULL) {
-		async_answer_0(rid, ENOMEM);
-		return;
-	}
+	if (fs == NULL)
+		return ENOMEM;
 	
 	/* Allocate instance structure */
@@ -627,6 +606,5 @@
 	if (inst == NULL) {
 		free(fs);
-		async_answer_0(rid, ENOMEM);
-		return;
+		return ENOMEM;
 	}
 	
@@ -636,6 +614,5 @@
 		free(fs);
 		free(inst);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 	
@@ -646,6 +623,5 @@
 		free(fs);
 		free(inst);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 	
@@ -656,6 +632,5 @@
 		free(fs);
 		free(inst);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 	
@@ -673,6 +648,5 @@
 		free(fs);
 		free(inst);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 	ext2fs_node_t *enode = EXT2FS_NODE(root_node);
@@ -683,22 +657,16 @@
 	fibril_mutex_unlock(&instance_list_mutex);
 	
-	async_answer_3(rid, EOK,
-	    EXT2_INODE_ROOT_INDEX,
-	    0,
-	    ext2_inode_get_usage_count(enode->inode_ref->inode));
+	*index = EXT2_INODE_ROOT_INDEX;
+	*size = 0;
+	*lnkcnt = ext2_inode_get_usage_count(enode->inode_ref->inode);
 	
 	ext2fs_node_put(root_node);
-}
-
-void ext2fs_mount(ipc_callid_t rid, ipc_call_t *request)
-{
-	EXT2FS_DBG("");
-	libfs_mount(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
-}
-
-void ext2fs_unmounted(ipc_callid_t rid, ipc_call_t *request)
-{
-	EXT2FS_DBG("");
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+
+	return EOK;
+}
+
+static int ext2fs_unmounted(devmap_handle_t devmap_handle)
+{
+	EXT2FS_DBG("");
 	ext2fs_instance_t *inst;
 	int rc;
@@ -706,8 +674,6 @@
 	rc = ext2fs_instance_get(devmap_handle, &inst);
 	
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
+	if (rc != EOK)
+		return rc;
 	
 	fibril_mutex_lock(&open_nodes_lock);
@@ -716,6 +682,5 @@
 	if (inst->open_nodes_count != 0) {
 		fibril_mutex_unlock(&open_nodes_lock);
-		async_answer_0(rid, EBUSY);
-		return;
+		return EBUSY;
 	}
 	
@@ -729,26 +694,12 @@
 	ext2_filesystem_fini(inst->filesystem);
 	
-	async_answer_0(rid, EOK);
-}
-
-void ext2fs_unmount(ipc_callid_t rid, ipc_call_t *request)
-{
-	EXT2FS_DBG("");
-	libfs_unmount(&ext2fs_libfs_ops, rid, request);
-}
-
-void ext2fs_lookup(ipc_callid_t rid, ipc_call_t *request)
-{
-	EXT2FS_DBG("");
-	libfs_lookup(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
-}
-
-void ext2fs_read(ipc_callid_t rid, ipc_call_t *request)
-{
-	EXT2FS_DBG("");
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	aoff64_t pos =
-	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	return EOK;
+}
+
+static int
+ext2fs_read(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+    size_t *rbytes)
+{
+	EXT2FS_DBG("");
 	
 	ext2fs_instance_t *inst;
@@ -763,6 +714,5 @@
 	if (!async_data_read_receive(&callid, &size)) {
 		async_answer_0(callid, EINVAL);
-		async_answer_0(rid, EINVAL);
-		return;
+		return EINVAL;
 	}
 	
@@ -770,6 +720,5 @@
 	if (rc != EOK) {
 		async_answer_0(callid, rc);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 	
@@ -777,24 +726,24 @@
 	if (rc != EOK) {
 		async_answer_0(callid, rc);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 	
 	if (ext2_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
-		    EXT2_INODE_MODE_FILE)) {
-		ext2fs_read_file(rid, callid, pos, size, inst, inode_ref);
-	}
-	else if (ext2_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
-		    EXT2_INODE_MODE_DIRECTORY)) {
-		ext2fs_read_directory(rid, callid, pos, size, inst, inode_ref);
-	}
-	else {
+	    EXT2_INODE_MODE_FILE)) {
+		rc = ext2fs_read_file(callid, pos, size, inst, inode_ref,
+		    rbytes);
+	} else if (ext2_inode_is_type(inst->filesystem->superblock,
+	    inode_ref->inode, EXT2_INODE_MODE_DIRECTORY)) {
+		rc = ext2fs_read_directory(callid, pos, size, inst, inode_ref,
+		    rbytes);
+	} else {
 		/* Other inode types not supported */
 		async_answer_0(callid, ENOTSUP);
-		async_answer_0(rid, ENOTSUP);
+		rc = ENOTSUP;
 	}
 	
 	ext2_filesystem_put_inode_ref(inode_ref);
 	
+	return rc;
 }
 
@@ -814,6 +763,6 @@
 }
 
-void ext2fs_read_directory(ipc_callid_t rid, ipc_callid_t callid, aoff64_t pos,
-	size_t size, ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref)
+int ext2fs_read_directory(ipc_callid_t callid, aoff64_t pos, size_t size,
+    ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref, size_t *rbytes)
 {
 	ext2_directory_iterator_t it;
@@ -827,6 +776,5 @@
 	if (rc != EOK) {
 		async_answer_0(callid, rc);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 	
@@ -841,5 +789,5 @@
 		
 		name_size = ext2_directory_entry_ll_get_name_length(
-			inst->filesystem->superblock, it.current);
+		    inst->filesystem->superblock, it.current);
 		
 		/* skip . and .. */
@@ -849,18 +797,17 @@
 		
 		/* The on-disk entry does not contain \0 at the end
-			* end of entry name, so we copy it to new buffer
-			* and add the \0 at the end
-			*/
+		 * end of entry name, so we copy it to new buffer
+		 * and add the \0 at the end
+		 */
 		buf = malloc(name_size+1);
 		if (buf == NULL) {
 			ext2_directory_iterator_fini(&it);
 			async_answer_0(callid, ENOMEM);
-			async_answer_0(rid, ENOMEM);
-			return;
+			return ENOMEM;
 		}
 		memcpy(buf, &it.current->name, name_size);
-		*(buf+name_size) = 0;
+		*(buf + name_size) = 0;
 		found = true;
-		(void) async_data_read_finalize(callid, buf, name_size+1);
+		(void) async_data_read_finalize(callid, buf, name_size + 1);
 		free(buf);
 		break;
@@ -871,6 +818,5 @@
 			ext2_directory_iterator_fini(&it);
 			async_answer_0(callid, rc);
-			async_answer_0(rid, rc);
-			return;
+			return rc;
 		}
 	}
@@ -878,28 +824,24 @@
 	if (found) {
 		rc = ext2_directory_iterator_next(&it);
-		if (rc != EOK) {
-			async_answer_0(rid, rc);
-			return;
-		}
+		if (rc != EOK)
+			return rc;
 		next = it.current_offset;
 	}
 	
 	rc = ext2_directory_iterator_fini(&it);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
+	if (rc != EOK)
+		return rc;
 	
 	if (found) {
-		async_answer_1(rid, EOK, next-pos);
-	}
-	else {
+		*rbytes = next - pos;
+		return EOK;
+	} else {
 		async_answer_0(callid, ENOENT);
-		async_answer_0(rid, ENOENT);
-	}
-}
-
-void ext2fs_read_file(ipc_callid_t rid, ipc_callid_t callid, aoff64_t pos,
-	size_t size, ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref)
+		return ENOENT;
+	}
+}
+
+int ext2fs_read_file(ipc_callid_t callid, aoff64_t pos, size_t size,
+    ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref, size_t *rbytes)
 {
 	int rc;
@@ -919,6 +861,6 @@
 		/* Read 0 bytes successfully */
 		async_data_read_finalize(callid, NULL, 0);
-		async_answer_1(rid, EOK, 0);
-		return;
+		*rbytes = 0;
+		return EOK;
 	}
 	
@@ -939,6 +881,5 @@
 	if (rc != EOK) {
 		async_answer_0(callid, rc);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 	
@@ -952,6 +893,5 @@
 		if (buffer == NULL) {
 			async_answer_0(callid, ENOMEM);
-			async_answer_0(rid, ENOMEM);
-			return;
+			return ENOMEM;
 		}
 		
@@ -959,9 +899,9 @@
 		
 		async_data_read_finalize(callid, buffer, bytes);
-		async_answer_1(rid, EOK, bytes);
+		*rbytes = bytes;
 		
 		free(buffer);
 		
-		return;
+		return EOK;
 	}
 	
@@ -970,6 +910,5 @@
 	if (rc != EOK) {
 		async_answer_0(callid, rc);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 	
@@ -978,75 +917,57 @@
 	
 	rc = block_put(block);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-		
-	async_answer_1(rid, EOK, bytes);
-}
-
-void ext2fs_write(ipc_callid_t rid, ipc_call_t *request)
-{
-	EXT2FS_DBG("");
-//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-//	aoff64_t pos =
-//	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
-	
-	// TODO
-	async_answer_0(rid, ENOTSUP);
-}
-
-void ext2fs_truncate(ipc_callid_t rid, ipc_call_t *request)
-{
-	EXT2FS_DBG("");
-//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-//	aoff64_t size =
-//	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
-	
-	// TODO
-	async_answer_0(rid, ENOTSUP);
-}
-
-void ext2fs_close(ipc_callid_t rid, ipc_call_t *request)
-{
-	EXT2FS_DBG("");
-	async_answer_0(rid, EOK);
-}
-
-void ext2fs_destroy(ipc_callid_t rid, ipc_call_t *request)
-{
-	EXT2FS_DBG("");
-//	devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
-//	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
-	
-	// TODO
-	async_answer_0(rid, ENOTSUP);
-}
-
-void ext2fs_open_node(ipc_callid_t rid, ipc_call_t *request)
-{
-	EXT2FS_DBG("");
-	libfs_open_node(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
-}
-
-void ext2fs_stat(ipc_callid_t rid, ipc_call_t *request)
-{
-	EXT2FS_DBG("");
-	libfs_stat(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
-}
-
-void ext2fs_sync(ipc_callid_t rid, ipc_call_t *request)
-{
-	EXT2FS_DBG("");
-//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	
-	// TODO
-	async_answer_0(rid, ENOTSUP);
-}
+	if (rc != EOK)
+		return rc;
+	
+	*rbytes = bytes;
+	return EOK;
+}
+
+static int
+ext2fs_write(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+    size_t *wbytes, aoff64_t *nsize)
+{
+	EXT2FS_DBG("");
+	return ENOTSUP;
+}
+
+static int
+ext2fs_truncate(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t size)
+{
+	EXT2FS_DBG("");
+	return ENOTSUP;
+}
+
+static int ext2fs_close(devmap_handle_t devmap_handle, fs_index_t index)
+{
+	EXT2FS_DBG("");
+	return EOK;
+}
+
+static int ext2fs_destroy(devmap_handle_t devmap_handle, fs_index_t index)
+{
+	EXT2FS_DBG("");
+	return ENOTSUP;
+}
+
+static int ext2fs_sync(devmap_handle_t devmap_handle, fs_index_t index)
+{
+	EXT2FS_DBG("");
+	return ENOTSUP;
+}
+
+vfs_out_ops_t ext2fs_ops = {
+	.mounted = ext2fs_mounted,
+	.unmounted = ext2fs_unmounted,
+	.read = ext2fs_read,
+	.write = ext2fs_write,
+	.truncate = ext2fs_truncate,
+	.close = ext2fs_close,
+	.destroy = ext2fs_destroy,
+	.sync = ext2fs_sync,
+};
 
 /**
  * @}
  */
+
Index: uspace/srv/fs/fat/fat.c
===================================================================
--- uspace/srv/fs/fat/fat.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/fs/fat/fat.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -56,91 +56,4 @@
 };
 
-fs_reg_t fat_reg;
-
-/**
- * This connection fibril processes VFS requests from VFS.
- *
- * In order to support simultaneous VFS requests, our design is as follows.
- * The connection fibril accepts VFS requests from VFS. If there is only one
- * instance of the fibril, VFS will need to serialize all VFS requests it sends
- * to FAT. To overcome this bottleneck, VFS can send FAT the IPC_M_CONNECT_ME_TO
- * call. In that case, a new connection fibril will be created, which in turn
- * will accept the call. Thus, a new phone will be opened for VFS.
- *
- * There are few issues with this arrangement. First, VFS can run out of
- * available phones. In that case, VFS can close some other phones or use one
- * phone for more serialized requests. Similarily, FAT can refuse to duplicate
- * the connection. VFS should then just make use of already existing phones and
- * route its requests through them. To avoid paying the fibril creation price 
- * upon each request, FAT might want to keep the connections open after the
- * request has been completed.
- */
-static void fat_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	if (iid) {
-		/*
-		 * This only happens for connections opened by
-		 * IPC_M_CONNECT_ME_TO calls as opposed to callback connections
-		 * created by IPC_M_CONNECT_TO_ME.
-		 */
-		async_answer_0(iid, EOK);
-	}
-	
-	dprintf(NAME ": connection opened\n");
-	
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call))
-			return;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case VFS_OUT_MOUNTED:
-			fat_mounted(callid, &call);
-			break;
-		case VFS_OUT_MOUNT:
-			fat_mount(callid, &call);
-			break;
-		case VFS_OUT_UNMOUNTED:
-			fat_unmounted(callid, &call);
-			break;
-		case VFS_OUT_UNMOUNT:
-			fat_unmount(callid, &call);
-			break;
-		case VFS_OUT_LOOKUP:
-			fat_lookup(callid, &call);
-			break;
-		case VFS_OUT_READ:
-			fat_read(callid, &call);
-			break;
-		case VFS_OUT_WRITE:
-			fat_write(callid, &call);
-			break;
-		case VFS_OUT_TRUNCATE:
-			fat_truncate(callid, &call);
-			break;
-		case VFS_OUT_STAT:
-			fat_stat(callid, &call);
-			break;
-		case VFS_OUT_CLOSE:
-			fat_close(callid, &call);
-			break;
-		case VFS_OUT_DESTROY:
-			fat_destroy(callid, &call);
-			break;
-		case VFS_OUT_OPEN_NODE:
-			fat_open_node(callid, &call);
-			break;
-		case VFS_OUT_SYNC:
-			fat_sync(callid, &call);
-			break;
-		default:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		}
-	}
-}
-
 int main(int argc, char **argv)
 {
@@ -158,5 +71,5 @@
 	}
 	
-	rc = fs_register(vfs_sess, &fat_reg, &fat_vfs_info, fat_connection);
+	rc = fs_register(vfs_sess, &fat_vfs_info, &fat_ops, &fat_libfs_ops);
 	if (rc != EOK) {
 		fat_idx_fini();
Index: uspace/srv/fs/fat/fat.h
===================================================================
--- uspace/srv/fs/fat/fat.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/fs/fat/fat.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -224,20 +224,6 @@
 } fat_node_t;
 
-extern fs_reg_t fat_reg;
-
-extern void fat_mounted(ipc_callid_t, ipc_call_t *);
-extern void fat_mount(ipc_callid_t, ipc_call_t *);
-extern void fat_unmounted(ipc_callid_t, ipc_call_t *);
-extern void fat_unmount(ipc_callid_t, ipc_call_t *);
-extern void fat_lookup(ipc_callid_t, ipc_call_t *);
-extern void fat_read(ipc_callid_t, ipc_call_t *);
-extern void fat_write(ipc_callid_t, ipc_call_t *);
-extern void fat_truncate(ipc_callid_t, ipc_call_t *);
-extern void fat_stat(ipc_callid_t, ipc_call_t *);
-extern void fat_close(ipc_callid_t, ipc_call_t *);
-extern void fat_destroy(ipc_callid_t, ipc_call_t *);
-extern void fat_open_node(ipc_callid_t, ipc_call_t *);
-extern void fat_stat(ipc_callid_t, ipc_call_t *);
-extern void fat_sync(ipc_callid_t, ipc_call_t *);
+extern vfs_out_ops_t fat_ops;
+extern libfs_ops_t fat_libfs_ops;
 
 extern int fat_idx_get_new(fat_idx_t **, devmap_handle_t);
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -85,5 +85,4 @@
 static aoff64_t fat_size_get(fs_node_t *);
 static unsigned fat_lnkcnt_get(fs_node_t *);
-static char fat_plb_get_char(unsigned);
 static bool fat_is_directory(fs_node_t *);
 static bool fat_is_file(fs_node_t *node);
@@ -901,9 +900,4 @@
 }
 
-char fat_plb_get_char(unsigned pos)
-{
-	return fat_reg.plb_ro[pos % PLB_SIZE];
-}
-
 bool fat_is_directory(fs_node_t *fn)
 {
@@ -936,5 +930,4 @@
 	.size_get = fat_size_get,
 	.lnkcnt_get = fat_lnkcnt_get,
-	.plb_get_char = fat_plb_get_char,
 	.is_directory = fat_is_directory,
 	.is_file = fat_is_file,
@@ -943,22 +936,15 @@
 
 /*
- * VFS operations.
+ * FAT VFS_OUT operations.
  */
 
-void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+static int
+fat_mounted(devmap_handle_t devmap_handle, const char *opts, fs_index_t *index,
+    aoff64_t *size, unsigned *linkcnt)
+{
 	enum cache_mode cmode;
 	fat_bs_t *bs;
-	
-	/* Accept the mount options */
-	char *opts;
-	int rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
-	
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-
+	int rc;
+	
 	/* Check for option enabling write through. */
 	if (str_cmp(opts, "wtcache") == 0)
@@ -967,12 +953,8 @@
 		cmode = CACHE_MODE_WB;
 
-	free(opts);
-
 	/* initialize libblock */
 	rc = block_init(EXCHANGE_SERIALIZE, devmap_handle, BS_SIZE);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
+	if (rc != EOK)
+		return rc;
 
 	/* prepare the boot block */
@@ -980,6 +962,5 @@
 	if (rc != EOK) {
 		block_fini(devmap_handle);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 
@@ -989,6 +970,5 @@
 	if (BPS(bs) != BS_SIZE) {
 		block_fini(devmap_handle);
-		async_answer_0(rid, ENOTSUP);
-		return;
+		return ENOTSUP;
 	}
 
@@ -997,6 +977,5 @@
 	if (rc != EOK) {
 		block_fini(devmap_handle);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 
@@ -1006,6 +985,5 @@
 		(void) block_cache_fini(devmap_handle);
 		block_fini(devmap_handle);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 
@@ -1014,6 +992,5 @@
 		(void) block_cache_fini(devmap_handle);
 		block_fini(devmap_handle);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 
@@ -1024,6 +1001,5 @@
 		block_fini(devmap_handle);
 		fat_idx_fini_by_devmap_handle(devmap_handle);
-		async_answer_0(rid, ENOMEM);
-		return;
+		return ENOMEM;
 	}
 	fs_node_initialize(rfn);
@@ -1034,6 +1010,5 @@
 		block_fini(devmap_handle);
 		fat_idx_fini_by_devmap_handle(devmap_handle);
-		async_answer_0(rid, ENOMEM);
-		return;
+		return ENOMEM;
 	}
 	fat_node_initialize(rootp);
@@ -1046,6 +1021,5 @@
 		block_fini(devmap_handle);
 		fat_idx_fini_by_devmap_handle(devmap_handle);
-		async_answer_0(rid, ENOMEM);
-		return;
+		return ENOMEM;
 	}
 	assert(ridxp->index == 0);
@@ -1064,15 +1038,13 @@
 	fibril_mutex_unlock(&ridxp->lock);
 
-	async_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt);
-}
-
-void fat_mount(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_mount(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
-}
-
-void fat_unmounted(ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	*index = ridxp->index;
+	*size = rootp->size;
+	*linkcnt = rootp->lnkcnt;
+
+	return EOK;
+}
+
+static int fat_unmounted(devmap_handle_t devmap_handle)
+{
 	fs_node_t *fn;
 	fat_node_t *nodep;
@@ -1080,8 +1052,6 @@
 
 	rc = fat_root_get(&fn, devmap_handle);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
+	if (rc != EOK)
+		return rc;
 	nodep = FAT_NODE(fn);
 
@@ -1092,6 +1062,5 @@
 	if (nodep->refcnt != 2) {
 		(void) fat_node_put(fn);
-		async_answer_0(rid, EBUSY);
-		return;
+		return EBUSY;
 	}
 	
@@ -1112,23 +1081,11 @@
 	block_fini(devmap_handle);
 
-	async_answer_0(rid, EOK);
-}
-
-void fat_unmount(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_unmount(&fat_libfs_ops, rid, request);
-}
-
-void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
-}
-
-void fat_read(ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	aoff64_t pos =
-	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	return EOK;
+}
+
+static int
+fat_read(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+    size_t *rbytes)
+{
 	fs_node_t *fn;
 	fat_node_t *nodep;
@@ -1139,12 +1096,8 @@
 
 	rc = fat_node_get(&fn, devmap_handle, index);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-	if (!fn) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
+	if (rc != EOK)
+		return rc;
+	if (!fn)
+		return ENOENT;
 	nodep = FAT_NODE(fn);
 
@@ -1154,6 +1107,5 @@
 		fat_node_put(fn);
 		async_answer_0(callid, EINVAL);
-		async_answer_0(rid, EINVAL);
-		return;
+		return EINVAL;
 	}
 
@@ -1178,6 +1130,5 @@
 				fat_node_put(fn);
 				async_answer_0(callid, rc);
-				async_answer_0(rid, rc);
-				return;
+				return rc;
 			}
 			(void) async_data_read_finalize(callid,
@@ -1186,6 +1137,5 @@
 			if (rc != EOK) {
 				fat_node_put(fn);
-				async_answer_0(rid, rc);
-				return;
+				return rc;
 			}
 		}
@@ -1244,12 +1194,11 @@
 		rc = fat_node_put(fn);
 		async_answer_0(callid, rc != EOK ? rc : ENOENT);
-		async_answer_1(rid, rc != EOK ? rc : ENOENT, 0);
-		return;
+		*rbytes = 0;
+		return rc != EOK ? rc : ENOENT;
 
 err:
 		(void) fat_node_put(fn);
 		async_answer_0(callid, rc);
-		async_answer_0(rid, rc);
-		return;
+		return rc;
 
 hit:
@@ -1259,17 +1208,16 @@
 
 	rc = fat_node_put(fn);
-	async_answer_1(rid, rc, (sysarg_t)bytes);
-}
-
-void fat_write(ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	aoff64_t pos =
-	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	*rbytes = bytes;
+	return rc;
+}
+
+static int
+fat_write(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+    size_t *wbytes, aoff64_t *nsize)
+{
 	fs_node_t *fn;
 	fat_node_t *nodep;
 	fat_bs_t *bs;
-	size_t bytes, size;
+	size_t bytes;
 	block_t *b;
 	aoff64_t boundary;
@@ -1278,12 +1226,8 @@
 	
 	rc = fat_node_get(&fn, devmap_handle, index);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-	if (!fn) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
+	if (rc != EOK)
+		return rc;
+	if (!fn)
+		return ENOENT;
 	nodep = FAT_NODE(fn);
 	
@@ -1293,6 +1237,5 @@
 		(void) fat_node_put(fn);
 		async_answer_0(callid, EINVAL);
-		async_answer_0(rid, EINVAL);
-		return;
+		return EINVAL;
 	}
 
@@ -1322,6 +1265,5 @@
 			(void) fat_node_put(fn);
 			async_answer_0(callid, rc);
-			async_answer_0(rid, rc);
-			return;
+			return rc;
 		}
 		rc = fat_block_get(&b, bs, nodep, pos / BPS(bs), flags);
@@ -1329,6 +1271,5 @@
 			(void) fat_node_put(fn);
 			async_answer_0(callid, rc);
-			async_answer_0(rid, rc);
-			return;
+			return rc;
 		}
 		(void) async_data_write_finalize(callid,
@@ -1338,6 +1279,5 @@
 		if (rc != EOK) {
 			(void) fat_node_put(fn);
-			async_answer_0(rid, rc);
-			return;
+			return rc;
 		}
 		if (pos + bytes > nodep->size) {
@@ -1345,8 +1285,8 @@
 			nodep->dirty = true;	/* need to sync node */
 		}
-		size = nodep->size;
+		*wbytes = bytes;
+		*nsize = nodep->size;
 		rc = fat_node_put(fn);
-		async_answer_2(rid, rc, bytes, nodep->size);
-		return;
+		return rc;
 	} else {
 		/*
@@ -1364,6 +1304,5 @@
 			(void) fat_node_put(fn);
 			async_answer_0(callid, rc);
-			async_answer_0(rid, rc);
-			return;
+			return rc;
 		}
 		/* zero fill any gaps */
@@ -1373,6 +1312,5 @@
 			(void) fat_node_put(fn);
 			async_answer_0(callid, rc);
-			async_answer_0(rid, rc);
-			return;
+			return rc;
 		}
 		rc = _fat_block_get(&b, bs, devmap_handle, lcl, NULL,
@@ -1382,6 +1320,5 @@
 			(void) fat_node_put(fn);
 			async_answer_0(callid, rc);
-			async_answer_0(rid, rc);
-			return;
+			return rc;
 		}
 		(void) async_data_write_finalize(callid,
@@ -1392,6 +1329,5 @@
 			(void) fat_free_clusters(bs, devmap_handle, mcl);
 			(void) fat_node_put(fn);
-			async_answer_0(rid, rc);
-			return;
+			return rc;
 		}
 		/*
@@ -1403,21 +1339,17 @@
 			(void) fat_free_clusters(bs, devmap_handle, mcl);
 			(void) fat_node_put(fn);
-			async_answer_0(rid, rc);
-			return;
-		}
-		nodep->size = size = pos + bytes;
+			return rc;
+		}
+		*nsize = nodep->size = pos + bytes;
+		rc = fat_node_put(fn);
 		nodep->dirty = true;		/* need to sync node */
-		rc = fat_node_put(fn);
-		async_answer_2(rid, rc, bytes, size);
-		return;
-	}
-}
-
-void fat_truncate(ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	aoff64_t size =
-	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+		*wbytes = bytes;
+		return rc;
+	}
+}
+
+static int
+fat_truncate(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t size)
+{
 	fs_node_t *fn;
 	fat_node_t *nodep;
@@ -1426,12 +1358,8 @@
 
 	rc = fat_node_get(&fn, devmap_handle, index);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-	if (!fn) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
+	if (rc != EOK)
+		return rc;
+	if (!fn)
+		return ENOENT;
 	nodep = FAT_NODE(fn);
 
@@ -1477,17 +1405,14 @@
 out:
 	fat_node_put(fn);
-	async_answer_0(rid, rc);
-	return;
-}
-
-void fat_close(ipc_callid_t rid, ipc_call_t *request)
-{
-	async_answer_0(rid, EOK);
-}
-
-void fat_destroy(ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
-	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
+	return rc;
+}
+
+static int fat_close(devmap_handle_t devmap_handle, fs_index_t index)
+{
+	return EOK;
+}
+
+static int fat_destroy(devmap_handle_t devmap_handle, fs_index_t index)
+{
 	fs_node_t *fn;
 	fat_node_t *nodep;
@@ -1495,12 +1420,8 @@
 
 	rc = fat_node_get(&fn, devmap_handle, index);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-	if (!fn) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
+	if (rc != EOK)
+		return rc;
+	if (!fn)
+		return ENOENT;
 
 	nodep = FAT_NODE(fn);
@@ -1512,32 +1433,15 @@
 
 	rc = fat_destroy_node(fn);
-	async_answer_0(rid, rc);
-}
-
-void fat_open_node(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_open_node(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
-}
-
-void fat_stat(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_stat(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
-}
-
-void fat_sync(ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	
+	return rc;
+}
+
+static int fat_sync(devmap_handle_t devmap_handle, fs_index_t index)
+{
 	fs_node_t *fn;
 	int rc = fat_node_get(&fn, devmap_handle, index);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-	if (!fn) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
+	if (rc != EOK)
+		return rc;
+	if (!fn)
+		return ENOENT;
 	
 	fat_node_t *nodep = FAT_NODE(fn);
@@ -1547,6 +1451,17 @@
 	
 	fat_node_put(fn);
-	async_answer_0(rid, rc);
-}
+	return rc;
+}
+
+vfs_out_ops_t fat_ops = {
+	.mounted = fat_mounted,
+	.unmounted = fat_unmounted,
+	.read = fat_read,
+	.write = fat_write,
+	.truncate = fat_truncate,
+	.close = fat_close,
+	.destroy = fat_destroy,
+	.sync = fat_sync,
+};
 
 /**
Index: uspace/srv/fs/tmpfs/tmpfs.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/fs/tmpfs/tmpfs.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -61,92 +61,4 @@
 };
 
-fs_reg_t tmpfs_reg;
-
-/**
- * This connection fibril processes VFS requests from VFS.
- *
- * In order to support simultaneous VFS requests, our design is as follows.
- * The connection fibril accepts VFS requests from VFS. If there is only one
- * instance of the fibril, VFS will need to serialize all VFS requests it sends
- * to FAT. To overcome this bottleneck, VFS can send TMPFS the
- * IPC_M_CONNECT_ME_TO call. In that case, a new connection fibril will be
- * created, which in turn will accept the call. Thus, a new phone will be
- * opened for VFS.
- *
- * There are few issues with this arrangement. First, VFS can run out of
- * available phones. In that case, VFS can close some other phones or use one
- * phone for more serialized requests. Similarily, TMPFS can refuse to duplicate
- * the connection. VFS should then just make use of already existing phones and
- * route its requests through them. To avoid paying the fibril creation price 
- * upon each request, TMPFS might want to keep the connections open after the
- * request has been completed.
- */
-static void tmpfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	if (iid) {
-		/*
-		 * This only happens for connections opened by
-		 * IPC_M_CONNECT_ME_TO calls as opposed to callback connections
-		 * created by IPC_M_CONNECT_TO_ME.
-		 */
-		async_answer_0(iid, EOK);
-	}
-	
-	dprintf(NAME ": connection opened\n");
-	
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call))
-			return;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case VFS_OUT_MOUNTED:
-			tmpfs_mounted(callid, &call);
-			break;
-		case VFS_OUT_MOUNT:
-			tmpfs_mount(callid, &call);
-			break;
-		case VFS_OUT_UNMOUNTED:
-			tmpfs_unmounted(callid, &call);
-			break;
-		case VFS_OUT_UNMOUNT:
-			tmpfs_unmount(callid, &call);
-			break;
-		case VFS_OUT_LOOKUP:
-			tmpfs_lookup(callid, &call);
-			break;
-		case VFS_OUT_READ:
-			tmpfs_read(callid, &call);
-			break;
-		case VFS_OUT_WRITE:
-			tmpfs_write(callid, &call);
-			break;
-		case VFS_OUT_TRUNCATE:
-			tmpfs_truncate(callid, &call);
-			break;
-		case VFS_OUT_CLOSE:
-			tmpfs_close(callid, &call);
-			break;
-		case VFS_OUT_DESTROY:
-			tmpfs_destroy(callid, &call);
-			break;
-		case VFS_OUT_OPEN_NODE:
-			tmpfs_open_node(callid, &call);
-			break;
-		case VFS_OUT_STAT:
-			tmpfs_stat(callid, &call);
-			break;
-		case VFS_OUT_SYNC:
-			tmpfs_sync(callid, &call);
-			break;
-		default:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		}
-	}
-}
-
 int main(int argc, char **argv)
 {
@@ -165,6 +77,6 @@
 	}
 	
-	int rc = fs_register(vfs_sess, &tmpfs_reg, &tmpfs_vfs_info,
-	    tmpfs_connection);
+	int rc = fs_register(vfs_sess, &tmpfs_vfs_info, &tmpfs_ops,
+	    &tmpfs_libfs_ops);
 	if (rc != EOK) {
 		printf(NAME ": Failed to register file system (%d)\n", rc);
Index: uspace/srv/fs/tmpfs/tmpfs.h
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/fs/tmpfs/tmpfs.h	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -70,24 +70,8 @@
 } tmpfs_node_t;
 
-extern fs_reg_t tmpfs_reg;
-
+extern vfs_out_ops_t tmpfs_ops;
 extern libfs_ops_t tmpfs_libfs_ops;
 
 extern bool tmpfs_init(void);
-
-extern void tmpfs_mounted(ipc_callid_t, ipc_call_t *);
-extern void tmpfs_mount(ipc_callid_t, ipc_call_t *);
-extern void tmpfs_unmounted(ipc_callid_t, ipc_call_t *);
-extern void tmpfs_unmount(ipc_callid_t, ipc_call_t *);
-extern void tmpfs_lookup(ipc_callid_t, ipc_call_t *);
-extern void tmpfs_read(ipc_callid_t, ipc_call_t *);
-extern void tmpfs_write(ipc_callid_t, ipc_call_t *);
-extern void tmpfs_truncate(ipc_callid_t, ipc_call_t *);
-extern void tmpfs_stat(ipc_callid_t, ipc_call_t *);
-extern void tmpfs_close(ipc_callid_t, ipc_call_t *);
-extern void tmpfs_destroy(ipc_callid_t, ipc_call_t *);
-extern void tmpfs_open_node(ipc_callid_t, ipc_call_t *);
-extern void tmpfs_sync(ipc_callid_t, ipc_call_t *);
-
 extern bool tmpfs_restore(devmap_handle_t);
 
Index: uspace/srv/fs/tmpfs/tmpfs_ops.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -104,9 +104,4 @@
 }
 
-static char tmpfs_plb_get_char(unsigned pos)
-{
-	return tmpfs_reg.plb_ro[pos % PLB_SIZE];
-}
-
 static bool tmpfs_is_directory(fs_node_t *fn)
 {
@@ -139,5 +134,4 @@
 	.size_get = tmpfs_size_get,
 	.lnkcnt_get = tmpfs_lnkcnt_get,
-	.plb_get_char = tmpfs_plb_get_char,
 	.is_directory = tmpfs_is_directory,
 	.is_file = tmpfs_is_file,
@@ -433,33 +427,25 @@
 }
 
-void tmpfs_mounted(ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+/*
+ * Implementation of the VFS_OUT interface.
+ */
+
+static int
+tmpfs_mounted(devmap_handle_t devmap_handle, const char *opts,
+    fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
+{
 	fs_node_t *rootfn;
 	int rc;
 	
-	/* Accept the mount options. */
-	char *opts;
-	rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
-	if (rc != EOK) {
-		async_answer_0(rid, rc);
-		return;
-	}
-
 	/* Check if this device is not already mounted. */
 	rc = tmpfs_root_get(&rootfn, devmap_handle);
 	if ((rc == EOK) && (rootfn)) {
 		(void) tmpfs_node_put(rootfn);
-		free(opts);
-		async_answer_0(rid, EEXIST);
-		return;
+		return EEXIST;
 	}
 
 	/* Initialize TMPFS instance. */
-	if (!tmpfs_instance_init(devmap_handle)) {
-		free(opts);
-		async_answer_0(rid, ENOMEM);
-		return;
-	}
+	if (!tmpfs_instance_init(devmap_handle))
+		return ENOMEM;
 
 	rc = tmpfs_root_get(&rootfn, devmap_handle);
@@ -467,46 +453,24 @@
 	tmpfs_node_t *rootp = TMPFS_NODE(rootfn);
 	if (str_cmp(opts, "restore") == 0) {
-		if (tmpfs_restore(devmap_handle))
-			async_answer_3(rid, EOK, rootp->index, rootp->size,
-			    rootp->lnkcnt);
-		else
-			async_answer_0(rid, ELIMIT);
-	} else {
-		async_answer_3(rid, EOK, rootp->index, rootp->size,
-		    rootp->lnkcnt);
-	}
-	free(opts);
-}
-
-void tmpfs_mount(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_mount(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
-}
-
-void tmpfs_unmounted(ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-
+		if (!tmpfs_restore(devmap_handle))
+			return ELIMIT;
+	}
+
+	*index = rootp->index;
+	*size = rootp->size;
+	*lnkcnt = rootp->lnkcnt;
+
+	return EOK;
+}
+
+static int tmpfs_unmounted(devmap_handle_t devmap_handle)
+{
 	tmpfs_instance_done(devmap_handle);
-	async_answer_0(rid, EOK);
-}
-
-void tmpfs_unmount(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_unmount(&tmpfs_libfs_ops, rid, request);
-}
-
-void tmpfs_lookup(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_lookup(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
-}
-
-void tmpfs_read(ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	aoff64_t pos =
-	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
-	
+	return EOK;
+}
+
+static int tmpfs_read(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+    size_t *rbytes)
+{
 	/*
 	 * Lookup the respective TMPFS node.
@@ -518,8 +482,6 @@
 	};
 	hlp = hash_table_find(&nodes, key);
-	if (!hlp) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
+	if (!hlp)
+		return ENOENT;
 	tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
 	    nh_link);
@@ -532,6 +494,5 @@
 	if (!async_data_read_receive(&callid, &size)) {
 		async_answer_0(callid, EINVAL);
-		async_answer_0(rid, EINVAL);
-		return;
+		return EINVAL;
 	}
 
@@ -556,6 +517,5 @@
 		if (lnk == NULL) {
 			async_answer_0(callid, ENOENT);
-			async_answer_1(rid, ENOENT, 0);
-			return;
+			return ENOENT;
 		}
 
@@ -567,17 +527,12 @@
 	}
 
-	/*
-	 * Answer the VFS_READ call.
-	 */
-	async_answer_1(rid, EOK, bytes);
-}
-
-void tmpfs_write(ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	aoff64_t pos =
-	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
-	
+	*rbytes = bytes;
+	return EOK;
+}
+
+static int
+tmpfs_write(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+    size_t *wbytes, aoff64_t *nsize)
+{
 	/*
 	 * Lookup the respective TMPFS node.
@@ -589,8 +544,6 @@
 	};
 	hlp = hash_table_find(&nodes, key);
-	if (!hlp) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
+	if (!hlp)
+		return ENOENT;
 	tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
 	    nh_link);
@@ -603,6 +556,5 @@
 	if (!async_data_write_receive(&callid, &size)) {
 		async_answer_0(callid, EINVAL);	
-		async_answer_0(rid, EINVAL);
-		return;
+		return EINVAL;
 	}
 
@@ -612,7 +564,7 @@
 	if (pos + size <= nodep->size) {
 		/* The file size is not changing. */
-		(void) async_data_write_finalize(callid, nodep->data + pos, size);
-		async_answer_2(rid, EOK, size, nodep->size);
-		return;
+		(void) async_data_write_finalize(callid, nodep->data + pos,
+		    size);
+		goto out;
 	}
 	size_t delta = (pos + size) - nodep->size;
@@ -627,6 +579,6 @@
 	if (!newdata) {
 		async_answer_0(callid, ENOMEM);
-		async_answer_2(rid, EOK, 0, nodep->size);
-		return;
+		size = 0;
+		goto out;
 	}
 	/* Clear any newly allocated memory in order to emulate gaps. */
@@ -635,14 +587,14 @@
 	nodep->data = newdata;
 	(void) async_data_write_finalize(callid, nodep->data + pos, size);
-	async_answer_2(rid, EOK, size, nodep->size);
-}
-
-void tmpfs_truncate(ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	aoff64_t size =
-	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
-	
+
+out:
+	*wbytes = size;
+	*nsize = nodep->size;
+	return EOK;
+}
+
+static int tmpfs_truncate(devmap_handle_t devmap_handle, fs_index_t index,
+    aoff64_t size)
+{
 	/*
 	 * Lookup the respective TMPFS node.
@@ -653,26 +605,17 @@
 	};
 	link_t *hlp = hash_table_find(&nodes, key);
-	if (!hlp) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
-	tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
-	    nh_link);
-	
-	if (size == nodep->size) {
-		async_answer_0(rid, EOK);
-		return;
-	}
-	
-	if (size > SIZE_MAX) {
-		async_answer_0(rid, ENOMEM);
-		return;
-	}
+	if (!hlp)
+		return ENOENT;
+	tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t, nh_link);
+	
+	if (size == nodep->size)
+		return EOK;
+	
+	if (size > SIZE_MAX)
+		return ENOMEM;
 	
 	void *newdata = realloc(nodep->data, size);
-	if (!newdata) {
-		async_answer_0(rid, ENOMEM);
-		return;
-	}
+	if (!newdata)
+		return ENOMEM;
 	
 	if (size > nodep->size) {
@@ -683,18 +626,14 @@
 	nodep->size = size;
 	nodep->data = newdata;
-	async_answer_0(rid, EOK);
-}
-
-void tmpfs_close(ipc_callid_t rid, ipc_call_t *request)
-{
-	async_answer_0(rid, EOK);
-}
-
-void tmpfs_destroy(ipc_callid_t rid, ipc_call_t *request)
-{
-	devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
-	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
-	int rc;
-
+	return EOK;
+}
+
+static int tmpfs_close(devmap_handle_t devmap_handle, fs_index_t index)
+{
+	return EOK;
+}
+
+static int tmpfs_destroy(devmap_handle_t devmap_handle, fs_index_t index)
+{
 	link_t *hlp;
 	unsigned long key[] = {
@@ -703,25 +642,12 @@
 	};
 	hlp = hash_table_find(&nodes, key);
-	if (!hlp) {
-		async_answer_0(rid, ENOENT);
-		return;
-	}
+	if (!hlp)
+		return ENOENT;
 	tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
 	    nh_link);
-	rc = tmpfs_destroy_node(FS_NODE(nodep));
-	async_answer_0(rid, rc);
-}
-
-void tmpfs_open_node(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_open_node(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
-}
-
-void tmpfs_stat(ipc_callid_t rid, ipc_call_t *request)
-{
-	libfs_stat(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
-}
-
-void tmpfs_sync(ipc_callid_t rid, ipc_call_t *request)
+	return tmpfs_destroy_node(FS_NODE(nodep));
+}
+
+static int tmpfs_sync(devmap_handle_t devmap_handle, fs_index_t index)
 {
 	/*
@@ -729,8 +655,20 @@
 	 * thus the sync operation is a no-op.
 	 */
-	async_answer_0(rid, EOK);
-}
+	return EOK;
+}
+
+vfs_out_ops_t tmpfs_ops = {
+	.mounted = tmpfs_mounted,
+	.unmounted = tmpfs_unmounted,
+	.read = tmpfs_read,
+	.write = tmpfs_write,
+	.truncate = tmpfs_truncate,
+	.close = tmpfs_close,
+	.destroy = tmpfs_destroy,
+	.sync = tmpfs_sync,
+};
 
 /**
  * @}
  */
+
Index: uspace/srv/loader/Makefile
===================================================================
--- uspace/srv/loader/Makefile	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/loader/Makefile	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -39,6 +39,4 @@
 LINKER_SCRIPT = $(LIBC_PREFIX)/arch/$(UARCH)/_link-loader.ld
 
-EXTRA_CFLAGS = -Iinclude
-
 BINARY = loader
 STATIC_ONLY = y
@@ -46,5 +44,4 @@
 GENERIC_SOURCES = \
 	main.c \
-	elf_load.c \
 	interp.s
 
Index: pace/srv/loader/elf_load.c
===================================================================
--- uspace/srv/loader/elf_load.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ 	(revision )
@@ -1,482 +1,0 @@
-/*
- * Copyright (c) 2006 Sergey Bondari
- * Copyright (c) 2006 Jakub Jermar
- * Copyright (c) 2011 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - 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.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-/** @addtogroup generic	
- * @{
- */
-
-/**
- * @file
- * @brief	Userspace ELF loader.
- *
- * This module allows loading ELF binaries (both executables and
- * shared objects) from VFS. The current implementation allocates
- * anonymous memory, fills it with segment data and then adjusts
- * the memory areas' flags to the final value. In the future,
- * the segments will be mapped directly from the file.
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <align.h>
-#include <assert.h>
-#include <as.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <smc.h>
-#include <loader/pcb.h>
-#include <entry_point.h>
-
-#include "elf.h"
-#include "elf_load.h"
-
-#define DPRINTF(...)
-
-static const char *error_codes[] = {
-	"no error",
-	"invalid image",
-	"address space error",
-	"incompatible image",
-	"unsupported image type",
-	"irrecoverable error"
-};
-
-static unsigned int elf_load(elf_ld_t *elf, size_t so_bias);
-static int segment_header(elf_ld_t *elf, elf_segment_header_t *entry);
-static int section_header(elf_ld_t *elf, elf_section_header_t *entry);
-static int load_segment(elf_ld_t *elf, elf_segment_header_t *entry);
-
-/** Read until the buffer is read in its entirety. */
-static int my_read(int fd, void *buf, size_t len)
-{
-	int cnt = 0;
-	do {
-		buf += cnt;
-		len -= cnt;
-		cnt = read(fd, buf, len);
-	} while ((cnt > 0) && ((len - cnt) > 0));
-
-	return cnt;
-}
-
-/** Load ELF binary from a file.
- *
- * Load an ELF binary from the specified file. If the file is
- * an executable program, it is loaded unbiased. If it is a shared
- * object, it is loaded with the bias @a so_bias. Some information
- * extracted from the binary is stored in a elf_info_t structure
- * pointed to by @a info.
- *
- * @param file_name Path to the ELF file.
- * @param so_bias   Bias to use if the file is a shared object.
- * @param info      Pointer to a structure for storing information
- *                  extracted from the binary.
- *
- * @return EOK on success or negative error code.
- *
- */
-int elf_load_file(const char *file_name, size_t so_bias, eld_flags_t flags,
-    elf_info_t *info)
-{
-	elf_ld_t elf;
-
-	int fd;
-	int rc;
-	
-	fd = open(file_name, O_RDONLY);
-	if (fd < 0) {
-		DPRINTF("failed opening file\n");
-		return -1;
-	}
-
-	elf.fd = fd;
-	elf.info = info;
-	elf.flags = flags;
-
-	rc = elf_load(&elf, so_bias);
-
-	close(fd);
-
-	return rc;
-}
-
-/** Create the program control block (PCB).
- *
- * Fills the program control block @a pcb with information from
- * @a info.
- *
- * @param info	Program info structure
- * @return EOK on success or negative error code
- */
-void elf_create_pcb(elf_info_t *info, pcb_t *pcb)
-{
-	pcb->entry = info->entry;
-	pcb->dynamic = info->dynamic;
-	pcb->rtld_runtime = NULL;
-}
-
-
-/** Load an ELF binary.
- *
- * The @a elf structure contains the loader state, including
- * an open file, from which the binary will be loaded,
- * a pointer to the @c info structure etc.
- *
- * @param elf		Pointer to loader state buffer.
- * @param so_bias	Bias to use if the file is a shared object.
- * @return EE_OK on success or EE_xx error code.
- */
-static unsigned int elf_load(elf_ld_t *elf, size_t so_bias)
-{
-	elf_header_t header_buf;
-	elf_header_t *header = &header_buf;
-	int i, rc;
-
-	rc = my_read(elf->fd, header, sizeof(elf_header_t));
-	if (rc < 0) {
-		DPRINTF("Read error.\n"); 
-		return EE_INVALID;
-	}
-
-	elf->header = header;
-
-	/* Identify ELF */
-	if (header->e_ident[EI_MAG0] != ELFMAG0 ||
-	    header->e_ident[EI_MAG1] != ELFMAG1 || 
-	    header->e_ident[EI_MAG2] != ELFMAG2 ||
-	    header->e_ident[EI_MAG3] != ELFMAG3) {
-		DPRINTF("Invalid header.\n");
-		return EE_INVALID;
-	}
-	
-	/* Identify ELF compatibility */
-	if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
-	    header->e_machine != ELF_MACHINE || 
-	    header->e_ident[EI_VERSION] != EV_CURRENT ||
-	    header->e_version != EV_CURRENT ||
-	    header->e_ident[EI_CLASS] != ELF_CLASS) {
-		DPRINTF("Incompatible data/version/class.\n");
-		return EE_INCOMPATIBLE;
-	}
-
-	if (header->e_phentsize != sizeof(elf_segment_header_t)) {
-		DPRINTF("e_phentsize:%d != %d\n", header->e_phentsize,
-		    sizeof(elf_segment_header_t));
-		return EE_INCOMPATIBLE;
-	}
-
-	if (header->e_shentsize != sizeof(elf_section_header_t)) {
-		DPRINTF("e_shentsize:%d != %d\n", header->e_shentsize,
-		    sizeof(elf_section_header_t));
-		return EE_INCOMPATIBLE;
-	}
-
-	/* Check if the object type is supported. */
-	if (header->e_type != ET_EXEC && header->e_type != ET_DYN) {
-		DPRINTF("Object type %d is not supported\n", header->e_type);
-		return EE_UNSUPPORTED;
-	}
-
-	/* Shared objects can be loaded with a bias */
-	if (header->e_type == ET_DYN)
-		elf->bias = so_bias;
-	else
-		elf->bias = 0;
-
-	elf->info->interp = NULL;
-	elf->info->dynamic = NULL;
-
-	/* Walk through all segment headers and process them. */
-	for (i = 0; i < header->e_phnum; i++) {
-		elf_segment_header_t segment_hdr;
-
-		/* Seek to start of segment header */
-		lseek(elf->fd, header->e_phoff
-		        + i * sizeof(elf_segment_header_t), SEEK_SET);
-
-		rc = my_read(elf->fd, &segment_hdr,
-		    sizeof(elf_segment_header_t));
-		if (rc < 0) {
-			DPRINTF("Read error.\n");
-			return EE_INVALID;
-		}
-
-		rc = segment_header(elf, &segment_hdr);
-		if (rc != EE_OK)
-			return rc;
-	}
-
-	DPRINTF("Parse sections.\n");
-
-	/* Inspect all section headers and proccess them. */
-	for (i = 0; i < header->e_shnum; i++) {
-		elf_section_header_t section_hdr;
-
-		/* Seek to start of section header */
-		lseek(elf->fd, header->e_shoff
-		    + i * sizeof(elf_section_header_t), SEEK_SET);
-
-		rc = my_read(elf->fd, &section_hdr,
-		    sizeof(elf_section_header_t));
-		if (rc < 0) {
-			DPRINTF("Read error.\n");
-			return EE_INVALID;
-		}
-
-		rc = section_header(elf, &section_hdr);
-		if (rc != EE_OK)
-			return rc;
-	}
-
-	elf->info->entry =
-	    (entry_point_t)((uint8_t *)header->e_entry + elf->bias);
-
-	DPRINTF("Done.\n");
-
-	return EE_OK;
-}
-
-/** Print error message according to error code.
- *
- * @param rc Return code returned by elf_load().
- *
- * @return NULL terminated description of error.
- */
-const char *elf_error(unsigned int rc)
-{
-	assert(rc < sizeof(error_codes) / sizeof(char *));
-
-	return error_codes[rc];
-}
-
-/** Process segment header.
- *
- * @param entry	Segment header.
- *
- * @return EE_OK on success, error code otherwise.
- */
-static int segment_header(elf_ld_t *elf, elf_segment_header_t *entry)
-{
-	switch (entry->p_type) {
-	case PT_NULL:
-	case PT_PHDR:
-	case PT_NOTE:
-		break;
-	case PT_LOAD:
-		return load_segment(elf, entry);
-		break;
-	case PT_INTERP:
-		/* Assume silently interp == "/app/dload" */
-		elf->info->interp = "/app/dload";
-		break;
-	case PT_DYNAMIC:
-		/* Record pointer to dynamic section into info structure */
-		elf->info->dynamic =
-		    (void *)((uint8_t *)entry->p_vaddr + elf->bias);
-		DPRINTF("dynamic section found at 0x%x\n",
-			(uintptr_t)elf->info->dynamic);
-		break;
-	case 0x70000000:
-		/* FIXME: MIPS reginfo */
-		break;
-	case PT_SHLIB:
-//	case PT_LOPROC:
-//	case PT_HIPROC:
-	default:
-		DPRINTF("Segment p_type %d unknown.\n", entry->p_type);
-		return EE_UNSUPPORTED;
-		break;
-	}
-	return EE_OK;
-}
-
-/** Load segment described by program header entry.
- *
- * @param elf	Loader state.
- * @param entry Program header entry describing segment to be loaded.
- *
- * @return EE_OK on success, error code otherwise.
- */
-int load_segment(elf_ld_t *elf, elf_segment_header_t *entry)
-{
-	void *a;
-	int flags = 0;
-	uintptr_t bias;
-	uintptr_t base;
-	void *seg_ptr;
-	uintptr_t seg_addr;
-	size_t mem_sz;
-	int rc;
-
-	bias = elf->bias;
-
-	seg_addr = entry->p_vaddr + bias;
-	seg_ptr = (void *) seg_addr;
-
-	DPRINTF("Load segment at addr %p, size 0x%x\n", (void *) seg_addr,
-		entry->p_memsz);
-
-	if (entry->p_align > 1) {
-		if ((entry->p_offset % entry->p_align) !=
-		    (seg_addr % entry->p_align)) {
-			DPRINTF("Align check 1 failed offset%%align=%d, "
-			    "vaddr%%align=%d\n",
-			    entry->p_offset % entry->p_align,
-			    seg_addr % entry->p_align
-			);
-			return EE_INVALID;
-		}
-	}
-
-	/* Final flags that will be set for the memory area */
-
-	if (entry->p_flags & PF_X)
-		flags |= AS_AREA_EXEC;
-	if (entry->p_flags & PF_W)
-		flags |= AS_AREA_WRITE;
-	if (entry->p_flags & PF_R)
-		flags |= AS_AREA_READ;
-	flags |= AS_AREA_CACHEABLE;
-	
-	base = ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE);
-	mem_sz = entry->p_memsz + (entry->p_vaddr - base);
-
-	DPRINTF("Map to seg_addr=%p-%p.\n", (void *) seg_addr,
-	    (void *) (entry->p_vaddr + bias +
-	    ALIGN_UP(entry->p_memsz, PAGE_SIZE)));
-
-	/*
-	 * For the course of loading, the area needs to be readable
-	 * and writeable.
-	 */
-	a = as_area_create((uint8_t *)base + bias, mem_sz,
-	    AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE);
-	if (a == (void *)(-1)) {
-		DPRINTF("memory mapping failed (0x%x, %d)\n",
-			base+bias, mem_sz);
-		return EE_MEMORY;
-	}
-
-	DPRINTF("as_area_create(%p, %#zx, %d) -> %p\n",
-	    (void *) (base + bias), mem_sz, flags, (void *) a);
-
-	/*
-	 * Load segment data
-	 */
-	rc = lseek(elf->fd, entry->p_offset, SEEK_SET);
-	if (rc < 0) {
-		printf("seek error\n");
-		return EE_INVALID;
-	}
-
-/*	rc = read(fd, (void *)(entry->p_vaddr + bias), entry->p_filesz);
-	if (rc < 0) { printf("read error\n"); return EE_INVALID; }*/
-
-	/* Long reads are not possible yet. Load segment piecewise. */
-
-	unsigned left, now;
-	uint8_t *dp;
-
-	left = entry->p_filesz;
-	dp = seg_ptr;
-
-	while (left > 0) {
-		now = 16384;
-		if (now > left) now = left;
-
-		rc = my_read(elf->fd, dp, now);
-
-		if (rc < 0) { 
-			DPRINTF("Read error.\n");
-			return EE_INVALID;
-		}
-
-		left -= now;
-		dp += now;
-	}
-
-	/*
-	 * The caller wants to modify the segments first. He will then
-	 * need to set the right access mode and ensure SMC coherence.
-	 */
-	if ((elf->flags & ELDF_RW) != 0) return EE_OK;
-
-//	printf("set area flags to %d\n", flags);
-	rc = as_area_change_flags(seg_ptr, flags);
-	if (rc != 0) {
-		DPRINTF("Failed to set memory area flags.\n");
-		return EE_MEMORY;
-	}
-
-	if (flags & AS_AREA_EXEC) {
-		/* Enforce SMC coherence for the segment */
-		if (smc_coherence(seg_ptr, entry->p_filesz))
-			return EE_MEMORY;
-	}
-
-	return EE_OK;
-}
-
-/** Process section header.
- *
- * @param elf	Loader state.
- * @param entry Segment header.
- *
- * @return EE_OK on success, error code otherwise.
- */
-static int section_header(elf_ld_t *elf, elf_section_header_t *entry)
-{
-	switch (entry->sh_type) {
-	case SHT_PROGBITS:
-		if (entry->sh_flags & SHF_TLS) {
-			/* .tdata */
-		}
-		break;
-	case SHT_NOBITS:
-		if (entry->sh_flags & SHF_TLS) {
-			/* .tbss */
-		}
-		break;
-	case SHT_DYNAMIC:
-		/* Record pointer to dynamic section into info structure */
-		elf->info->dynamic =
-		    (void *)((uint8_t *)entry->sh_addr + elf->bias);
-		DPRINTF("Dynamic section found at %p.\n",
-		    (void *) elf->info->dynamic);
-		break;
-	default:
-		break;
-	}
-	
-	return EE_OK;
-}
-
-/** @}
- */
Index: pace/srv/loader/include/elf.h
===================================================================
--- uspace/srv/loader/include/elf.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ 	(revision )
@@ -1,344 +1,0 @@
-/*
- * Copyright (c) 2006 Sergey Bondari
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - 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.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-/** @addtogroup generic	
- * @{
- */
-/** @file
- */
-
-#ifndef ELF_H_
-#define ELF_H_
-
-#include <arch/elf.h>
-#include <sys/types.h>
-
-/**
- * current ELF version
- */
-#define	EV_CURRENT	1
-
-/** 
- * ELF types 
- */
-#define ET_NONE		0	/* No type */
-#define ET_REL		1	/* Relocatable file */
-#define ET_EXEC		2	/* Executable */
-#define ET_DYN		3	/* Shared object */
-#define ET_CORE		4	/* Core */
-#define ET_LOPROC	0xff00	/* Processor specific */
-#define ET_HIPROC	0xffff	/* Processor specific */
-
-/** 
- * ELF machine types
- */
-#define EM_NO		0	/* No machine */
-#define EM_SPARC	2	/* SPARC */
-#define EM_386		3	/* i386 */
-#define EM_MIPS		8	/* MIPS RS3000 */
-#define EM_MIPS_RS3_LE	10	/* MIPS RS3000 LE */
-#define EM_PPC		20	/* PPC32 */
-#define EM_PPC64	21	/* PPC64 */
-#define EM_ARM		40	/* ARM */
-#define EM_SPARCV9	43	/* SPARC64 */
-#define EM_IA_64	50	/* IA-64 */
-#define EM_X86_64	62	/* AMD64/EMT64 */
-
-/**
- * ELF identification indexes
- */
-#define EI_MAG0		0
-#define EI_MAG1		1
-#define EI_MAG2		2
-#define EI_MAG3		3
-#define EI_CLASS	4		/* File class */
-#define EI_DATA		5		/* Data encoding */
-#define EI_VERSION	6		/* File version */
-#define EI_OSABI	7
-#define EI_ABIVERSION	8
-#define EI_PAD		9		/* Start of padding bytes */
-#define EI_NIDENT	16		/* ELF identification table size */
-
-/**
- * ELF magic number
- */
-#define ELFMAG0		0x7f
-#define ELFMAG1		'E'
-#define ELFMAG2		'L'
-#define ELFMAG3		'F'
-
-/**
- * ELF file classes
- */
-#define ELFCLASSNONE	0
-#define ELFCLASS32	1
-#define ELFCLASS64	2
-
-/**
- * ELF data encoding types
- */
-#define ELFDATANONE	0
-#define ELFDATA2LSB	1		/* Least significant byte first (little endian) */
-#define ELFDATA2MSB	2		/* Most signigicant byte first (big endian) */
-
-/**
- * ELF error return codes
- */
-#define EE_OK			0	/* No error */
-#define EE_INVALID		1	/* Invalid ELF image */
-#define	EE_MEMORY		2	/* Cannot allocate address space */
-#define EE_INCOMPATIBLE		3	/* ELF image is not compatible with current architecture */
-#define EE_UNSUPPORTED		4	/* Non-supported ELF (e.g. dynamic ELFs) */
-#define EE_IRRECOVERABLE	5
-
-/**
- * ELF section types
- */
-#define SHT_NULL		0
-#define SHT_PROGBITS		1
-#define SHT_SYMTAB		2
-#define SHT_STRTAB		3
-#define SHT_RELA		4
-#define SHT_HASH		5
-#define SHT_DYNAMIC		6
-#define SHT_NOTE		7
-#define SHT_NOBITS		8
-#define SHT_REL			9
-#define SHT_SHLIB		10
-#define SHT_DYNSYM		11
-#define SHT_LOOS		0x60000000
-#define SHT_HIOS		0x6fffffff
-#define SHT_LOPROC		0x70000000
-#define SHT_HIPROC		0x7fffffff
-#define SHT_LOUSER		0x80000000
-#define SHT_HIUSER		0xffffffff
-
-/**
- * ELF section flags
- */
-#define SHF_WRITE		0x1 
-#define SHF_ALLOC		0x2
-#define SHF_EXECINSTR		0x4
-#define SHF_TLS			0x400
-#define SHF_MASKPROC		0xf0000000
-
-/**
- * Symbol binding
- */
-#define STB_LOCAL		0
-#define STB_GLOBAL		1
-#define STB_WEAK		2
-#define STB_LOPROC		13
-#define STB_HIPROC		15
-
-/**
- * Symbol types
- */
-#define STT_NOTYPE		0
-#define STT_OBJECT		1
-#define STT_FUNC		2
-#define STT_SECTION		3
-#define STT_FILE		4
-#define STT_LOPROC		13
-#define STT_HIPROC		15
-
-/**
- * Program segment types
- */
-#define PT_NULL			0
-#define PT_LOAD			1
-#define PT_DYNAMIC		2
-#define PT_INTERP		3
-#define PT_NOTE			4
-#define PT_SHLIB		5
-#define PT_PHDR			6
-#define PT_LOPROC		0x70000000
-#define PT_HIPROC		0x7fffffff
-
-/**
- * Program segment attributes.
- */
-#define PF_X	1
-#define PF_W	2
-#define PF_R	4
-
-/**
- * ELF data types
- *
- * These types are found to be identical in both 32-bit and 64-bit
- * ELF object file specifications. They are the only types used
- * in ELF header.
- */
-typedef uint64_t elf_xword;
-typedef int64_t elf_sxword;
-typedef uint32_t elf_word;
-typedef int32_t elf_sword;
-typedef uint16_t elf_half;
-
-/**
- * 32-bit ELF data types.
- *
- * These types are specific for 32-bit format.
- */
-typedef uint32_t elf32_addr;
-typedef uint32_t elf32_off;
-
-/**
- * 64-bit ELF data types.
- *
- * These types are specific for 64-bit format.
- */
-typedef uint64_t elf64_addr;
-typedef uint64_t elf64_off;
-
-/** ELF header */
-struct elf32_header {
-	uint8_t e_ident[EI_NIDENT];
-	elf_half e_type;
-	elf_half e_machine;
-	elf_word e_version;
-	elf32_addr e_entry;
-	elf32_off e_phoff;
-	elf32_off e_shoff;
-	elf_word e_flags;
-	elf_half e_ehsize;
-	elf_half e_phentsize;
-	elf_half e_phnum;
-	elf_half e_shentsize;
-	elf_half e_shnum;
-	elf_half e_shstrndx;
-};
-struct elf64_header {
-	uint8_t e_ident[EI_NIDENT];
-	elf_half e_type;
-	elf_half e_machine;
-	elf_word e_version;
-	elf64_addr e_entry;
-	elf64_off e_phoff;
-	elf64_off e_shoff;
-	elf_word e_flags;
-	elf_half e_ehsize;
-	elf_half e_phentsize;
-	elf_half e_phnum;
-	elf_half e_shentsize;
-	elf_half e_shnum;
-	elf_half e_shstrndx;
-};
-
-/*
- * ELF segment header.
- * Segments headers are also known as program headers.
- */
-struct elf32_segment_header {
-	elf_word p_type;
-	elf32_off p_offset;
-	elf32_addr p_vaddr;
-	elf32_addr p_paddr;
-	elf_word p_filesz;
-	elf_word p_memsz;
-	elf_word p_flags;
-	elf_word p_align;
-};
-struct elf64_segment_header {
-	elf_word p_type;
-	elf_word p_flags;
-	elf64_off p_offset;
-	elf64_addr p_vaddr;
-	elf64_addr p_paddr;
-	elf_xword p_filesz;
-	elf_xword p_memsz;
-	elf_xword p_align;
-};
-
-/*
- * ELF section header
- */
-struct elf32_section_header {
-	elf_word sh_name;
-	elf_word sh_type;
-	elf_word sh_flags;
-	elf32_addr sh_addr;
-	elf32_off sh_offset;
-	elf_word sh_size;
-	elf_word sh_link;
-	elf_word sh_info;
-	elf_word sh_addralign;
-	elf_word sh_entsize;
-};
-struct elf64_section_header {
-	elf_word sh_name;
-	elf_word sh_type;
-	elf_xword sh_flags;
-	elf64_addr sh_addr;
-	elf64_off sh_offset;
-	elf_xword sh_size;
-	elf_word sh_link;
-	elf_word sh_info;
-	elf_xword sh_addralign;
-	elf_xword sh_entsize;
-};
-
-/*
- * ELF symbol table entry
- */
-struct elf32_symbol {
-	elf_word st_name;
-	elf32_addr st_value;
-	elf_word st_size;
-	uint8_t st_info;
-	uint8_t st_other;
-	elf_half st_shndx;
-};
-struct elf64_symbol {
-	elf_word st_name;
-	uint8_t st_info;
-	uint8_t st_other;
-	elf_half st_shndx;
-	elf64_addr st_value;
-	elf_xword st_size;
-};
-
-#ifdef __32_BITS__ 
-typedef struct elf32_header elf_header_t;
-typedef struct elf32_segment_header elf_segment_header_t;
-typedef struct elf32_section_header elf_section_header_t;
-typedef struct elf32_symbol elf_symbol_t;
-#endif
-#ifdef __64_BITS__
-typedef struct elf64_header elf_header_t;
-typedef struct elf64_segment_header elf_segment_header_t;
-typedef struct elf64_section_header elf_section_header_t;
-typedef struct elf64_symbol elf_symbol_t;
-#endif
-
-extern const char *elf_error(unsigned int rc);
-
-#endif
-
-/** @}
- */
Index: pace/srv/loader/include/elf_load.h
===================================================================
--- uspace/srv/loader/include/elf_load.h	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ 	(revision )
@@ -1,91 +1,0 @@
-/*
- * Copyright (c) 2008 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - 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.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- */
-
-/** @addtogroup generic
- * @{
- */
-/** @file
- * @brief ELF loader structures and public functions.
- */
-
-#ifndef ELF_LOAD_H_
-#define ELF_LOAD_H_
-
-#include <arch/elf.h>
-#include <sys/types.h>
-#include <loader/pcb.h>
-
-#include "elf.h"
-
-typedef enum {
-	/** Leave all segments in RW access mode. */
-	ELDF_RW = 1
-} eld_flags_t;
-
-/**
- * Some data extracted from the headers are stored here
- */
-typedef struct {
-	/** Entry point */
-	entry_point_t entry;
-
-	/** ELF interpreter name or NULL if statically-linked */
-	const char *interp;
-
-	/** Pointer to the dynamic section */
-	void *dynamic;
-} elf_info_t;
-
-/**
- * Holds information about an ELF binary being loaded.
- */
-typedef struct {
-	/** Filedescriptor of the file from which we are loading */
-	int fd;
-
-	/** Difference between run-time addresses and link-time addresses */
-	uintptr_t bias;
-
-	/** Flags passed to the ELF loader. */
-	eld_flags_t flags;
-
-	/** A copy of the ELF file header */
-	elf_header_t *header;
-
-	/** Store extracted info here */
-	elf_info_t *info;
-} elf_ld_t;
-
-int elf_load_file(const char *file_name, size_t so_bias, eld_flags_t flags,
-    elf_info_t *info);
-void elf_create_pcb(elf_info_t *info, pcb_t *pcb);
-
-#endif
-
-/** @}
- */
Index: uspace/srv/loader/main.c
===================================================================
--- uspace/srv/loader/main.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/loader/main.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -59,6 +59,6 @@
 #include <str.h>
 #include <as.h>
-#include <elf.h>
-#include <elf_load.h>
+#include <elf/elf.h>
+#include <elf/elf_load.h>
 
 #ifdef CONFIG_RTLD
@@ -348,6 +348,6 @@
 
 	/* Initialize list of loaded modules */
-	list_initialize(&runtime_env->modules_head);
-	list_append(&prog_mod.modules_link, &runtime_env->modules_head);
+	list_initialize(&runtime_env->modules);
+	list_append(&prog_mod.modules_link, &runtime_env->modules);
 
 	/* Pointer to program module. Used as root of the module graph. */
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision 2f02ee250338aee19a583527f440b7d38366cbcb)
+++ uspace/srv/vfs/vfs_ops.c	(revision 056d682116b138703a3b3af7ef219756be38f916)
@@ -76,5 +76,5 @@
 	vfs_node_t *mr_node;
 	fs_index_t rindex;
-	size_t rsize;
+	aoff64_t rsize;
 	unsigned rlnkcnt;
 	async_exch_t *exch;
@@ -146,6 +146,6 @@
 
 			rindex = (fs_index_t) IPC_GET_ARG1(answer);
-			rsize = (size_t) IPC_GET_ARG2(answer);
-			rlnkcnt = (unsigned) IPC_GET_ARG3(answer);
+			rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
+			rlnkcnt = (unsigned) IPC_GET_ARG4(answer);
 			
 			mr_res.triplet.fs_handle = fs_handle;
@@ -229,6 +229,7 @@
 	if (rc == EOK) {
 		rindex = (fs_index_t) IPC_GET_ARG1(answer);
-		rsize = (size_t) IPC_GET_ARG2(answer);
-		rlnkcnt = (unsigned) IPC_GET_ARG3(answer);
+		rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
+		    IPC_GET_ARG3(answer));
+		rlnkcnt = (unsigned) IPC_GET_ARG4(answer);
 		
 		mr_res.triplet.fs_handle = fs_handle;
@@ -795,14 +796,14 @@
 	ipc_call_t answer;
 	if (read) {
-		rc = async_data_read_forward_3_1(fs_exch, VFS_OUT_READ,
-		    file->node->devmap_handle, file->node->index, file->pos,
-		    &answer);
+		rc = async_data_read_forward_4_1(fs_exch, VFS_OUT_READ,
+		    file->node->devmap_handle, file->node->index,
+		    LOWER32(file->pos), UPPER32(file->pos), &answer);
 	} else {
 		if (file->append)
 			file->pos = file->node->size;
 		
-		rc = async_data_write_forward_3_1(fs_exch, VFS_OUT_WRITE,
-		    file->node->devmap_handle, file->node->index, file->pos,
-		    &answer);
+		rc = async_data_write_forward_4_1(fs_exch, VFS_OUT_WRITE,
+		    file->node->devmap_handle, file->node->index,
+		    LOWER32(file->pos), UPPER32(file->pos), &answer);
 	}
 	
@@ -821,5 +822,6 @@
 		/* Update the cached version of node's size. */
 		if (rc == EOK)
-			file->node->size = IPC_GET_ARG2(answer); 
+			file->node->size = MERGE_LOUP32(IPC_GET_ARG2(answer),
+			    IPC_GET_ARG3(answer));
 		fibril_rwlock_write_unlock(&file->node->contents_rwlock);
 	}
