rump: Port of the rump kernels to Genode

For further information see: http://wiki.netbsd.org/rumpkernel/. In this version
I ported the central rump components to Genode in order to take advantage of
NetBSD file system implementation. The new 'dde_rump' repository contains the
Genode version of the rump libraries and a 'rump_fs' server that implements
Genode file-system-session interface. Currently ext2, iso9660, and fat
file-systems are supported.

Issue #1048
This commit is contained in:
Sebastian Sumpf 2013-12-05 15:45:14 +01:00 committed by Christian Helmuth
parent ce27985b8a
commit 9251b1ede8
40 changed files with 4138 additions and 101 deletions

2
.gitignore vendored
View File

@ -17,6 +17,8 @@
/dde_linux/download
/dde_oss/contrib
/dde_oss/download
/dde_rump/contrib
/dde_rump/include/rump
/libports/contrib
/libports/download
/libports/include/curl/

64
dde_rump/Makefile Normal file
View File

@ -0,0 +1,64 @@
#
# \brief Checkout rump kernel source code
# \author Sebastian Sumpf
# \date 2013-11-27
#
VERBOSE ?= @
CONTRIB_DIR = contrib
ECHO = @echo
PATCHES := $(shell find patches -name \*.patch)
GIT_RUMP_URI = https://github.com/anttikantee/buildrump.sh.git
GIT_RUMP_COMMIT = d604845baafa110945cb54a2d9607e6f435c6027
GIT_LIBS_URI = https://github.com/anttikantee/xen-nblibc.git
GIT_LIBS_COMMIT = b86122315f338042d06ad83ac5bd763a5dbd0c00
RUMP_SRC = src
#
# Utility to check if a tool is installed
#
check_tool = $(if $(shell which $(1)),,$(error Need to have '$(1)' installed.))
$(call check_tool,git)
$(CONTRIB_DIR)/.git:
$(VERBOSE) git clone $(GIT_RUMP_URI) $(CONTRIB_DIR)
$(CONTRIB_DIR)/nblibs:
$(VERBOSE) git clone $(GIT_LIBS_URI) $(CONTRIB_DIR)/nblibs
cd $(CONTRIB_DIR)/nblibs ; ln -sf ../$(RUMP_SRC)/common
$(CONTRIB_DIR)/$(RUMP_SRC):
$(VERBOSE) cd $(CONTRIB_DIR); ./buildrump.sh -s $(RUMP_SRC) checkout
commit:
$(VERBOSE) cd $(CONTRIB_DIR); git fetch origin
$(VERBOSE) cd $(CONTRIB_DIR); git reset --hard $(GIT_RUMP_COMMIT)
$(VERBOSE) cd $(CONTRIB_DIR)/nblibs; git fetch origin
$(VERBOSE) cd $(CONTRIB_DIR)/nblibs; git reset --hard $(GIT_LIBS_COMMIT)
$(ECHO) "applying patches to '$(CONTRIB_DIR)/'"
$(VERBOSE)for i in $(PATCHES); do patch -N -d $(CONTRIB_DIR) -p1 < $$i; done
prepare: $(CONTRIB_DIR)/.git $(CONTRIB_DIR)/nblibs $(CONTRIB_DIR)/$(RUMP_SRC) commit
$(VERBOSE)mkdir -p include
$(VERBOSE)ln -sf ../$(CONTRIB_DIR)/$(RUMP_SRC)/sys/rump/include/rump include/rump
clean:
$(VERBOSE) rm -rf $(CONTRIB_DIR)
help::
$(ECHO)
$(ECHO) "Check out rump kernel sources"
$(ECHO)
$(ECHO) "The source code will be located at the '$(CONTRIB_DIR)/' directory."
$(ECHO)
$(ECHO) "--- available commands ---"
$(ECHO) "prepare - checkout source codes"
$(ECHO) "clean - remove source codes"
$(ECHO)
.NOTPARALLEL:

57
dde_rump/README Normal file
View File

@ -0,0 +1,57 @@
================================
Genode's Rump Kernel kernel port
================================
This repository contains the Genode version of the [http://wiki.netbsd.org/rumpkernel/ - rump kernel].
The kernel is currently used to gain file-system access from within Genode. In
order to achieve that, a Genode file-system server is located at
_src/server/rump_fs_. For accessing the server through the libc, the _libc_fs_
plugin can be facilitated, which is available in the _libports_ repository.
Building instructions
#####################
In order to build the file-system server, issue
! make prepare
from the directory this file is contained in.
Add
! REPOSITORIES += $(GENODE_DIR)/dde_rump
to your _etc/build.conf_ file of you build directory.
Finally,
! make server/rumps_fs
called from your build directory will build the server. You may also specify
! make run/rump_ext2
to run a simple test scenario.
Configuration
#############
Here is an example snippet that configures the server:
!<start name="rump_fs">
! <resource name="RAM" quantum="8M" />
! <provides><service name="File_system"/></provides>
! <config fs="ext2fs"><policy label="" root="/" writeable="yes"/></config>
!</start>
The server is looking for a service that provides a Genode block session. If
there is more than one block session in the system, the block session must be
routed to the right block-session server. The value of the _fs_ attribute of
the _config_ node can be one of the following: _ext2fs_ for EXT2, _cd9660_ for
ISO-9660, or _msdos_ for FAT file-system support. _root_ defines the directory
of the file system as seen as root directory by the client. The server hands
most of its RAM quota to the rump kernel. This means the larger the quota is,
the larger the internal block caches of the rump kernel will be.

View File

@ -0,0 +1,32 @@
/**
* \brief Definitions for FS front-end
* \author Sebastian Sumpf
* \date 2014-01-22
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__RUMP_FS__FS_H_
#define _INCLUDE__RUMP_FS__FS_H_
/**
* File to upon the back-end will open a block session
*/
#define GENODE_BLOCK_SESSION "block_session"
/**
* Device to create within rump
*/
#define GENODE_DEVICE "/genode"
/**
* Sync I/O back-end with underlying Genode subsystems
*/
void rump_io_backend_sync();
#endif /* _INCLUDE__RUMP_FS__FS_H_ */

View File

@ -0,0 +1,219 @@
/**
* \brief Fast allocator for porting
* \author Sebastian Sumpf
* \date 2013-06-12
*/
/*
* Copyright (C) 2013-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__UTIL__ALLOCATOR_FAP_H_
#define _INCLUDE__UTIL__ALLOCATOR_FAP_H_
#include <base/allocator_avl.h>
#include <dataspace/client.h>
#include <rm_session/connection.h>
namespace Allocator {
template <unsigned VM_SIZE, typename POLICY> class Backend_alloc;
template <unsigned VM_SIZE, typename POLICY> class Fap;
}
namespace Allocator {
using namespace Genode;
struct Default_allocator_policy
{
static int block() { return 0; }
static void unblock(int) { }
};
template <typename POLICY>
struct Policy_guard
{
int val;
Policy_guard() { val = POLICY::block(); }
~Policy_guard() { POLICY::unblock(val); }
};
/**
* Back-end allocator for Genode's slab allocator
*/
template <unsigned VM_SIZE, typename POLICY = Default_allocator_policy>
class Backend_alloc : public Genode::Allocator,
public Genode::Rm_connection
{
private:
enum {
BLOCK_SIZE = 1024 * 1024, /* 1 MB */
ELEMENTS = VM_SIZE / BLOCK_SIZE, /* MAX number of dataspaces in VM */
};
typedef Genode::addr_t addr_t;
typedef Genode::Ram_dataspace_capability Ram_dataspace_capability;
typedef Genode::Allocator_avl Allocator_avl;
addr_t _base; /* virt. base address */
bool _cached; /* non-/cached RAM */
Ram_dataspace_capability _ds_cap[ELEMENTS]; /* dataspaces to put in VM */
addr_t _ds_phys[ELEMENTS]; /* physical bases of dataspaces */
int _index = 0; /* current index in ds_cap */
Allocator_avl _range; /* manage allocations */
bool _quota_exceeded = false;
bool _alloc_block()
{
if (_quota_exceeded)
return false;
if (_index == ELEMENTS) {
PERR("Slab-backend exhausted!");
return false;
}
Policy_guard<POLICY> guard;
try {
_ds_cap[_index] = Genode::env()->ram_session()->alloc(BLOCK_SIZE, _cached);
/* attach at index * BLOCK_SIZE */
Rm_connection::attach_at(_ds_cap[_index], _index * BLOCK_SIZE, BLOCK_SIZE, 0);
/* lookup phys. address */
_ds_phys[_index] = Genode::Dataspace_client(_ds_cap[_index]).phys_addr();
} catch (Genode::Ram_session::Quota_exceeded) {
PERR("Backend allocator exhausted");
_quota_exceeded = true;
return false;
} catch (Genode::Rm_session::Attach_failed) {
PERR("Backend VM region exhausted");
_quota_exceeded = true;
return false;
}
/* return base + offset in VM area */
addr_t block_base = _base + (_index * BLOCK_SIZE);
++_index;
_range.add_range(block_base, BLOCK_SIZE);
return true;
}
public:
Backend_alloc(bool cached)
: Rm_connection(0, VM_SIZE), _cached(cached),
_range(Genode::env()->heap())
{
/* reserver attach us, anywere */
_base = Genode::env()->rm_session()->attach(dataspace());
}
/**
* Allocate
*/
bool alloc(size_t size, void **out_addr)
{
bool done = _range.alloc(size, out_addr);
if (done)
return done;
done = _alloc_block();
if (!done) {
PERR("Backend allocator exhausted\n");
return false;
}
return _range.alloc(size, out_addr);
}
void *alloc_aligned(size_t size, int align = 0)
{
void *addr;
if (!_range.alloc_aligned(size, &addr, align).is_error())
return addr;
if (!_alloc_block())
return 0;
if (_range.alloc_aligned(size, &addr, align).is_error()) {
PERR("Backend allocator: Unable to allocate memory (size: %zu align: %d:)",
size, align);
return 0;
}
return addr;
}
void free(void *addr, size_t size) { _range.free(addr, size); }
size_t overhead(size_t size) { return 0; }
bool need_size_for_free() const override { return false; }
/**
* Return phys address for given virtual addr.
*/
addr_t phys_addr(addr_t addr)
{
if (addr < _base || addr >= (_base + VM_SIZE))
return ~0UL;
int index = (addr - _base) / BLOCK_SIZE;
/* physical base of dataspace */
addr_t phys = _ds_phys[index];
if (!phys)
return ~0UL;
/* add offset */
phys += (addr - _base - (index * BLOCK_SIZE));
return phys;
}
bool inside(addr_t addr) const { return (addr >= _base) && (addr < (_base + VM_SIZE)); }
};
/**
* Interface
*/
template <unsigned VM_SIZE, typename POLICY = Default_allocator_policy>
class Fap
{
private:
typedef Allocator::Backend_alloc<VM_SIZE, POLICY> Backend_alloc;
Backend_alloc _back_allocator;
public:
Fap(bool cached)
: _back_allocator(cached) { }
void *alloc(size_t size, int align = 0)
{
return _back_allocator.alloc_aligned(size, align);
}
void free(void *addr, size_t size)
{
_back_allocator.free(addr, size);
}
addr_t phys_addr(void *addr)
{
return _back_allocator.phys_addr((addr_t)addr);
}
};
} /* namespace Allocator */
#endif /* _INCLUDE__UTIL__ALLOCATOR_FAP_H_ */

View File

@ -0,0 +1,65 @@
/**
* \brief Hard-context for use within rump kernel
* \author Sebastian Sumpf
* \date 2014-02-05
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__HARD_CONTEXT_H_
#define _INCLUDE__HARD_CONTEXT_H_
extern "C" {
#include <sys/cdefs.h>
#include <sys/types.h>
#include <rump/rump.h>
}
#include <base/thread.h>
/*************
** Threads **
*************/
typedef void *(*func)(void *);
namespace Timer {
class Connection;
};
class Hard_context : public Genode::Thread<sizeof(Genode::addr_t) * 2048>
{
private:
func _func;
void *_arg;
int _cookie;
lwp *_lwp;
protected:
void entry()
{
_func(_arg);
PDBG("Returned from func");
}
public:
Hard_context(char const *name, func f, void *arg, int cookie, bool run = true)
: Thread(name),
_func(f), _arg(arg), _cookie(cookie), _lwp(0) { if (run) start(); }
void set_lwp(lwp *l) { _lwp = l; }
lwp *get_lwp() { return _lwp; }
static Timer::Connection *timer();
};
#endif /* _INCLUDE__HARD_CONTEXT_H_ */

View File

@ -0,0 +1 @@
INC_DIR += $(LIBGCC_INC_DIR) $(BUILD_BASE_DIR)/var/libcache/rump/include

View File

@ -0,0 +1,4 @@
RUMP_OPT =
include $(REP_DIR)/lib/mk/rump_base.inc

23
dde_rump/lib/mk/rump.inc Normal file
View File

@ -0,0 +1,23 @@
#
# \brief Basic definitions for all rump libraries
# \author Sebastian Sumpf
# \date 2013-12-12
#
CONTRIB_DIR = $(REP_DIR)/contrib
RUMP_BASE = $(BUILD_BASE_DIR)/var/libcache/rump
RUMP_LIB = $(RUMP_BASE)/lib
SHARED_LIB = yes
#
# ARCHIVE contains the absolute paths to rump-archive libraries, rump.ld is an
# additional linker script which is required during initialization
#
LD_OPT += --whole-archive --start-group $(ARCHIVE) --end-group \
--no-whole-archiv
LD_SCRIPT_SO = $(call select_from_repositories,src/platform/genode_rel.ld) \
-T$(REP_DIR)/src/platform/rump.ld
# vi:set ft=make :

View File

@ -0,0 +1,92 @@
include $(REP_DIR)/lib/mk/rump.inc
include $(REP_DIR)/lib/import/import-rump.mk
RUMP_OBJ = $(RUMP_BASE)/obj
RUMP_SRC = $(CONTRIB_DIR)/src
RUMP_TOOLS = $(RUMP_BASE)/tools
RMAKE = $(RUMP_TOOLS)/rumpmake
#
# Can be up to 4 for most verbose output
#
VERBOSE_LEVEL ?= 0
#
# Sources
#
SRC_CC = dummies.cc hypercall.cc bootstrap.cc io.cc sync.cc
#
# TARGET to trigger rump build
#
SOURCE = $(addprefix $(REP_DIR)/src/lib/rump/,$(SRC_CC))
#
# Rump build script
#
BUILD_CMD = AR=$(AR) NM=$(NM) OBJCOPY=$(OBJCOPY) \
$(CONTRIB_DIR)/buildrump.sh -k -V'MAKEVERBOSE=$(VERBOSE_LEVEL)' \
$(RUMP_OPT) -s $(RUMP_SRC) -T $(RUMP_TOOLS) -o $(RUMP_OBJ) \
-d $(RUMP_BASE)
#
# Linkage
#
ARCHIVE = $(RUMP_LIB)/librump.a
CC_OPT = -DLIBRUMPUSER
INCSDIRS = adosfs altq arpa crypto dev evbarm filecorefs fs i386 isofs miscfs \
msdosfs net net80211 netatalk netbt netinet netinet6 netipsec \
netisdn netkey netmpls netnatm netsmb nfs ntfs ppath prop \
protocols rpc rpcsvc ssp sys ufs uvm x86
#
# Make sure include directory exists
#
$(shell mkdir -p $(RUMP_BASE)/include)
#
# Build nbmake for host platform
#
$(RUMP_TOOLS):
CC=$(CC) $(BUILD_CMD) -N -V RUMP_KERNEL_IS_LIBC=1 tools
echo 'CPPFLAGS+=-DMAXPHYS=32768' >> $(RUMP_TOOLS)/mk.conf
echo 'CPPFLAGS+= -fPIC' >> $(RUMP_TOOLS)/mk.conf
#
# Setup install directory
#
$(RUMP_OBJ)/dest: $(RUMP_TOOLS)
CC=$(CC) $(BUILD_CMD) setupdest
#
# Build librump
#
$(ARCHIVE): $(RUMP_OBJ)/dest
@echo "Building rump library ..."
CC=$(CC) $(BUILD_CMD) -k build install
#
# Install kernel, libc, and pthread headers
#
$(RUMP_BASE)/include/.prepared: $(ARCHIVE)
@for i in $(INCSDIRS); do \
mkdir -p $(RUMP_BASE)/include/$$i; done
@echo "Installing headers ... (this may take a while)"
@cd $(RUMP_SRC)/sys; $(RMAKE) -k obj >/dev/null 2>&1
@cd $(RUMP_SRC)/sys; $(RMAKE) -k includes >/dev/null 2>&1
@cd $(RUMP_SRC)/include; $(RMAKE) -k includes > /dev/null 2>&1
@cd $(CONTRIB_DIR)/nblibs/lib/libc; $(RMAKE) includes >/dev/null 2>&1
@cd $(CONTRIB_DIR)/nblibs/lib/libpthread; $(RMAKE) includes >/dev/null 2>&1
@touch $(RUMP_BASE)/include/.prepared
#
# Trigger rump build
#
$(SOURCE): $(RUMP_BASE)/include/.prepared
vpath %.cc $(REP_DIR)/src/lib/rump
# vi:set ft=make :

View File

@ -0,0 +1,23 @@
include $(REP_DIR)/lib/mk/rump.inc
LIBS += rump
RUMP_LIBS = librumpdev.a \
librumpdev_disk.a \
librumpdev_netsmb.a \
librumpkern_crypto.a \
librumpnet.a \
librumpvfs.a \
librumpfs_cd9660.a \
librumpfs_ext2fs.a \
librumpfs_ffs.a \
librumpfs_msdos.a \
librumpfs_nfs.a \
librumpfs_ntfs.a \
librumpfs_smbfs.a \
librumpfs_udf.a
ARCHIVE += $(addprefix $(RUMP_LIB)/,$(RUMP_LIBS))

View File

@ -0,0 +1,4 @@
RUMP_OPT = -32
include $(REP_DIR)/lib/mk/rump_base.inc

View File

@ -0,0 +1,4 @@
RUMP_OPT =
include $(REP_DIR)/lib/mk/rump_base.inc

View File

@ -0,0 +1,57 @@
diff --git a/buildrump.sh b/buildrump.sh
index f600b6a..e394b47 100755
--- a/buildrump.sh
+++ b/buildrump.sh
@@ -570,6 +570,16 @@ evaltools ()
: ${NM:=nm}
: ${OBJCOPY:=objcopy}
else
+ if [ "${MACH_ARCH}" = 'x86_64' ] ; then
+ cc_target=genode-x86
+ elif [ "${MACH_ARCH}" = 'arm' ] ; then
+ cc_target=genode-arm
+ else
+ die Unsupported architectur ${MACH_ARCH}
+ fi
+
+ echo "MACH_ARCH cc ${MACH_ARCH}"
+
: ${AR:=${cc_target}-ar}
: ${NM:=${cc_target}-nm}
: ${OBJCOPY:=${cc_target}-objcopy}
@@ -600,6 +610,8 @@ evaltools ()
;;
esac
+ TARGET=freebsd
+
# check if we're running from a tarball, i.e. is checkout possible
BRDIR=$(dirname $0)
unset TARBALLMODE
@@ -872,26 +884,6 @@ evaltarget ()
ccdefault=32
fi
- # step 2: if the user specified 32/64, try to establish if it will work
- if ${THIRTYTWO} && [ "${ccdefault}" -ne 32 ] ; then
- echo 'int main() {return 0;}' | ${CC} ${EXTRA_CFLAGS} -o /dev/null -x c - \
- ${EXTRA_RUMPUSER} ${EXTRA_RUMPCOMMON} > /dev/null 2>&1
- [ $? -eq 0 ] || ${ANYTARGETISGOOD} || \
- die 'Gave -32, but probe shows it will not work. Try -H?'
- elif ${SIXTYFOUR} && [ "${ccdefault}" -ne 64 ] ; then
- echo 'int main() {return 0;}' | ${CC} ${EXTRA_CFLAGS} -o /dev/null -x c - \
- ${EXTRA_RUMPUSER} ${EXTRA_RUMPCOMMON} > /dev/null 2>&1
- [ $? -eq 0 ] || ${ANYTARGETISGOOD} || \
- die 'Gave -64, but probe shows it will not work. Try -H?'
- else
- # not specified. use compiler default
- if [ "${ccdefault}" -eq 64 ]; then
- SIXTYFOUR=true
- else
- THIRTYTWO=true
- fi
- fi
-
TOOLABI=''
case ${MACH_ARCH} in
"amd64"|"x86_64")

View File

@ -0,0 +1,26 @@
diff --git a/src/sys/arch/arm/include/Makefile.common b/src/sys/arch/arm/include/Makefile.common
index 6d7643a..c91f55c 100644
--- a/src/sys/arch/arm/include/Makefile.common
+++ b/src/sys/arch/arm/include/Makefile.common
@@ -2,7 +2,7 @@
.PATH: ../../arm/include/common
-.if 0
+.if 1
INCS+= ansi.h aout_machdep.h asm.h \
bswap.h \
cdefs.h cpu.h \
diff --git a/src/sys/arch/evbarm/Makefile b/src/sys/arch/evbarm/Makefile
index c4340cb..ec9445b 100644
--- a/src/sys/arch/evbarm/Makefile
+++ b/src/sys/arch/evbarm/Makefile
@@ -3,7 +3,7 @@
# Makefile for evbarm tags file and boot blocks
# Find where ARM source files are for inclusion in tags
-.include <../arm/Makefile.inc>
+#.include <../arm/Makefile.inc>
TEVBARM= ${SYSDIR}/arch/evbarm/tags
SEVBARM= ${SYSDIR}/arch/evbarm/adi_brh/*.[ch]

13
dde_rump/patches/mk.patch Normal file
View File

@ -0,0 +1,13 @@
diff --git a/share/mk/bsd.own.mk b/share/mk/bsd.own.mk
index 57f4909..36235db 100644
--- a/src/share/mk/bsd.own.mk
+++ b/src/share/mk/bsd.own.mk
@@ -1045,7 +1045,7 @@ INSTPRIV?= ${INSTPRIV.unpriv} -N ${NETBSDSRCDIR}/etc
STRIPFLAG?=
.if ${NEED_OWN_INSTALL_TARGET} != "no"
-INSTALL_DIR?= ${INSTALL} ${INSTPRIV} -d
+INSTALL_DIR = ${INSTALL} ${INSTPRIV} -d
INSTALL_FILE?= ${INSTALL} ${INSTPRIV} ${COPY} ${PRESERVE} ${RENAME}
INSTALL_LINK?= ${INSTALL} ${INSTPRIV} ${HRDLINK} ${RENAME}
INSTALL_SYMLINK?= ${INSTALL} ${INSTPRIV} ${SYMLINK} ${RENAME}

View File

@ -0,0 +1,89 @@
#
# Check used commands
#
set mke2fs [check_installed mke2fs]
set dd [check_installed dd]
#
# Build
#
set build_components {
core init
drivers/timer
server/ram_blk
server/rump_fs
test/libc_fs
}
build $build_components
#
# Build EXT2-file-system image
#
catch { exec $dd if=/dev/zero of=bin/ext2.raw bs=1M count=16 }
catch { exec $mke2fs -F bin/ext2.raw }
create_boot_directory
#
# Generate config
#
append config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL" />
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="ram_blk">
<resource name="RAM" quantum="20M"/>
<provides><service name="Block"/></provides>
<config file="ext2.raw" block_size="512"/>
</start>
<start name="rump_fs">
<resource name="RAM" quantum="8M" />
<provides><service name="File_system"/></provides>
<config fs="ext2fs"><policy label="" root="/" writeable="yes"/></config>
</start>
<start name="test-libc_fs">
<resource name="RAM" quantum="4M"/>
</start>
</config>}
install_config $config
#
# Boot modules
#
# generic modules
set boot_modules {
core init timer test-libc_fs ram_blk
rump.lib.so rump_fs.lib.so rump_fs
ld.lib.so ext2.raw libc.lib.so
libc_fs.lib.so libc_log.lib.so
}
build_boot_image $boot_modules
append qemu_args " -m 256 -nographic"
run_genode_until {.*child exited with exit value 0.*} 60
exec rm -f bin/ext2.raw
puts "\nTest succeeded\n"

89
dde_rump/run/rump_fat.run Normal file
View File

@ -0,0 +1,89 @@
#
# Check used commands
#
set mkfs.vfat [check_installed mkfs.vfat]
set dd [check_installed dd]
#
# Build
#
set build_components {
core init
drivers/timer
server/ram_blk
server/rump_fs
test/libc_fs
}
build $build_components
#
# Build FAT-file-system image
#
catch { exec $dd if=/dev/zero of=bin/fs.raw bs=1M count=16 }
catch { exec $mkfs.vfat -F16 bin/fs.raw }
create_boot_directory
#
# Generate config
#
append config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL" />
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="ram_blk">
<resource name="RAM" quantum="20M"/>
<provides><service name="Block"/></provides>
<config file="fs.raw" block_size="512"/>
</start>
<start name="rump_fs">
<resource name="RAM" quantum="8M" />
<provides><service name="File_system"/></provides>
<config fs="msdos"><policy label="" root="/" writeable="yes"/></config>
</start>
<start name="test-libc_fs">
<resource name="RAM" quantum="4M"/>
</start>
</config>}
install_config $config
#
# Boot modules
#
# generic modules
set boot_modules {
core init timer test-libc_fs ram_blk
rump.lib.so rump_fs.lib.so rump_fs
ld.lib.so fs.raw libc.lib.so
libc_fs.lib.so libc_log.lib.so
}
build_boot_image $boot_modules
append qemu_args " -m 256 -nographic"
run_genode_until {.*child exited with exit value 0.*} 60
exec rm -f bin/fs.raw
puts "\nTest succeeded\n"

124
dde_rump/run/rump_iso.run Normal file
View File

@ -0,0 +1,124 @@
#
# Check used commands
#
set mkisofs [check_installed mkisofs]
#
#
# Build
#
set build_components {
core init
drivers/timer
server/fs_rom
server/rom_blk
server/rump_fs
test/iso
}
build $build_components
create_boot_directory
#
# Generate config
#
append config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL" />
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="rom_blk">
<resource name="RAM" quantum="2M"/>
<provides><service name="Block"/></provides>
<config file="fs.iso" block_size="2048"/>
</start>
<start name="rump_fs">
<resource name="RAM" quantum="8M" />
<provides><service name="File_system"/></provides>
<config fs="cd9660"><policy label="" root="/" writeable="no"/></config>
</start>
<start name="fs_rom">
<resource name="RAM" quantum="2M"/>
<provides><service name="ROM"/></provides>
</start>
<start name="test-iso">
<resource name="RAM" quantum="1M" />
<route>
<service name="ROM"><child name="fs_rom"/></service>
<any-service> <parent/> <any-child /> </any-service>
</route>
</start>
</config>}
#
# Create iso
#
exec cp -f [genode_dir]/os/src/test/iso/test.txt [run_dir]
for { set i 1 } { $i <= 30 } { incr i } {
exec touch [run_dir]/$i.txt
}
exec rm -f bin/fs.iso
catch { exec $mkisofs -l -R -hide-rr-moved -jcharset utf-8 -o bin/fs.iso [run_dir]}
install_config $config
#
# Boot modules
#
set boot_modules {
core init timer test-iso rom_blk
rump.lib.so rump_fs.lib.so rump_fs
ld.lib.so fs.iso fs_rom
}
build_boot_image $boot_modules
append qemu_args "-nographic -m 64"
run_genode_until "child exited with exit value 0.*\n" 60
# pay only attention to the output of init and its children
grep_output {^\[init -> test-iso}
unify_output {at [a-f0-9]+} "at <unified>"
compare_output_to {
[init -> test-iso] File size is 31000 at <unified>
[init -> test-iso] 00001000: 61616161 61616161 61616161 61616161 61616161
[init -> test-iso] 00001014: 61616161 61616161 61616161 61616161 61616161
[init -> test-iso] 00001028: 61616161 61616161 61616161 61616161 61616161
[init -> test-iso] 0000103c: 61616161 61616161 61616161 61616161 61616161
[init -> test-iso]
[init -> test-iso] 00010000: 62626262 62626262 62626262 62626262 62626262
[init -> test-iso] 00010014: 62626262 62626262 62626262 62626262 62626262
[init -> test-iso] 00010028: 62626262 62626262 62626262 62626262 62626262
[init -> test-iso] 0001003c: 62626262 62626262 62626262 62626262 62626262
[init -> test-iso]
[init -> test-iso] 00020000: 63636363 63636363 63636363 63636363 63636363
[init -> test-iso] 00020014: 63636363 63636363 63636363 63636363 63636363
[init -> test-iso] 00020028: 63636363 63636363 63636363 63636363 63636363
[init -> test-iso] 0002003c: 63636363 63636363 63636363 63636363 63636363
[init -> test-iso]
}

View File

@ -0,0 +1,258 @@
/*
* \brief Call initialization functions for all modules and components
* \author Sebastian Sumpf
* \date 2013-12-12
*/
/*
* Copyright (C) 2013-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
extern "C" {
#include <sys/types.h>
#include <rump/rumpuser.h>
#include <elf.h>
}
#include <base/env.h>
#include <base/printf.h>
#include <util/string.h>
#include "dl_interface.h"
extern "C" void wait_for_continue();
#ifdef _LP64
typedef Elf64_Dyn Elf_Dyn;
typedef Elf64_Sym Elf_Sym;
#else
typedef Elf32_Dyn Elf_Dyn;
typedef Elf32_Sym Elf_Sym;
#endif
static bool const verbose = false;
static void *dl_main;
struct Sym_tab
{
link_map *map;
void const *dynamic_base = 0;
void const *sym_base = 0;
Elf_Addr str_tab = 0;
size_t sym_cnt = 0;
size_t out_cnt = 0;
size_t str_size = 0;
Elf_Sym *sym_tab;
Sym_tab(link_map *map) : map(map), dynamic_base(map->l_ld)
{
if (!dynamic_base) {
PERR("%s: base is bogus %lx", map->l_name, map->l_addr);
throw -1;
}
if (verbose)
PDBG("for %s at %lx\n", map->l_name, map->l_addr);
find_tables();
if (!sym_base) {
PERR("%s: could not find symbol table (sym_base %p)", map->l_name,
sym_base);
throw -2;
}
/* alloc memory for the tables */
alloc_memory();
/* file sym_tab and str_tab */
read_symbols();
}
~Sym_tab()
{
if (sym_tab)
destroy(Genode::env()->heap(), sym_tab);
}
Elf_Sym const *elf_symbol(int index = 0)
{
Elf_Sym const *s = static_cast<Elf_Sym const *>(sym_base);
return &s[index];
}
Elf_Dyn const *elf_dyn(int index = 0)
{
Elf_Dyn const *d = static_cast<Elf_Dyn const *>(dynamic_base);
return &d[index];
}
bool is_wanted(char const *name)
{
using namespace Genode;
return (!strcmp(name, "rump", 4) ||
!strcmp(name, "RUMP", 4) ||
!strcmp(name, "__", 2)) ? true : false;
}
/**
* Find symtab and strtab
*/
void find_tables()
{
uint64_t dyn_tag = elf_dyn()->d_tag;
for (int i = 0;
dyn_tag != DT_NULL;
i++,
dyn_tag = elf_dyn(i)->d_tag) {
switch (dyn_tag) {
case DT_SYMTAB:
sym_base = (void *)(elf_dyn(i)->d_un.d_ptr + map->l_addr);
break;
case DT_STRTAB:
str_tab = elf_dyn(i)->d_un.d_ptr + map->l_addr;
break;
case DT_STRSZ:
str_size = elf_dyn(i)->d_un.d_ptr;
break;
case DT_HASH:
{
Elf_Symindx *hashtab = (Elf_Symindx *)(elf_dyn(i)->d_un.d_ptr +
map->l_addr);
sym_cnt = hashtab[1];
}
break;
case DT_SYMENT:
{
size_t sym_size = elf_dyn(i)->d_un.d_ptr;
if (sym_size != sizeof(Elf_Sym))
PWRN("Elf symbol size does not match binary %zx != elf %zx",
sym_size, sizeof(Elf_Sym));
}
default:
break;
}
}
}
void alloc_memory()
{
sym_tab = (Elf_Sym *)Genode::env()->heap()->alloc(sizeof(Elf_Sym) * sym_cnt);
}
void read_symbols()
{
for (unsigned i = 0; i < sym_cnt; i++) {
Elf_Sym const *sym = elf_symbol(i);
if (sym->st_shndx == SHN_UNDEF || !sym->st_value)
continue;
char const *name = (char const *)sym->st_name + str_tab;
if (!is_wanted(name))
continue;
sym_tab[out_cnt] = *sym;
/* set absolute value */
sym_tab[out_cnt].st_value += map->l_addr;
if (verbose)
PDBG("Read symbol %s val: %x", name, sym_tab[out_cnt].st_value);
out_cnt++;
}
}
void rump_load(rump_symload_fn symload)
{
symload(sym_tab, sizeof(Elf_Sym) * out_cnt, (char *)str_tab, str_size);
}
};
char const *_filename(char const *path)
{
int i;
int len = Genode::strlen(path);
for (i = len; i > 0 && path[i] != '/'; i--) ;
return path + i + 1;
}
/**
* Call init functions of libraries
*/
static void _dl_init(link_map const *map,
rump_modinit_fn mod_init,
rump_compload_fn comp_init)
{
void *handle = dlopen(map->l_name, RTLD_LAZY);
if (!handle)
PERR ("Could not dlopen %s\n", map->l_name);
struct modinfo **mi_start, **mi_end;
struct rump_component **rc_start, **rc_end;
mi_start = (modinfo **)dlsym(handle, "__start_link_set_modules");
mi_end = (modinfo **)dlsym(handle, "__stop_link_set_modules");
if (verbose)
PDBG("MI: start: %p end: %p", mi_start, mi_end);
if (mi_start && mi_end)
mod_init(mi_start, (size_t)(mi_end-mi_start));
rc_start = (rump_component **)dlsym(handle, "__start_link_set_rump_components");
rc_end = (rump_component **)dlsym(handle, "__stop_link_set_rump_components");
if (verbose)
PDBG("RC: start: %p end: %p", rc_start, rc_end);
if (rc_start && rc_end) {
for (; rc_start < rc_end; rc_start++)
comp_init(*rc_start);
}
}
void rumpuser_dl_bootstrap(rump_modinit_fn domodinit, rump_symload_fn symload,
rump_compload_fn compload)
{
/* open main program and request link map */
dl_main = dlopen(0, RTLD_NOW);
struct link_map *map;
if(dlinfo(dl_main, RTLD_DI_LINKMAP, &map)) {
PERR("Error: Could not retrieve linkmap from main program");
return;
}
for (; map->l_next; map = map->l_next) ;
struct link_map *curr_map;
for (curr_map = map; curr_map; curr_map = curr_map->l_prev)
if (!Genode::strcmp(_filename(curr_map->l_name), "rump", 4)) {
Sym_tab tab(curr_map);
/* load into rum kernel */
tab.rump_load(symload);
/* init modules and components */
_dl_init(curr_map, domodinit, compload);
}
PINF("BOOTSTRAP");
}
void * rumpuser_dl_globalsym(const char *symname)
{
void *addr = dlsym(RTLD_DEFAULT, symname);
if (verbose)
PDBG("Lookup: %s addr %p", symname, addr);
return addr;
}

View File

@ -0,0 +1,70 @@
/*
* \brief DL interface to the dynamic linker (since we don't rely on libc)
*
* These "weak" function should never be reached, because they are
* intercepted by ouer dynamic linker, if you see an error message than
* you program might not be a dynamic one.
*
* \author Sebastian Sumpf
* \date 2013-13-13
*/
/*
* Copyright (C) 2013-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _DL_INTERFACE_H_
#define _DL_INTERFACE_H_
#include <base/printf.h>
extern "C" {
/**
* dlopen
*/
enum Open_mode { RTLD_LAZY = 1, RTLD_NOW = 2 };
void __attribute__((weak))
*dlopen(const char *name, int mode)
{
PERR("dlopen: Local function called");
return 0;
}
/**
* dlinfo
*/
enum Reqeust { RTLD_DI_LINKMAP = 2 };
struct link_map {
unsigned long l_addr; /* Base Address of library */
const char *l_name; /* Absolute Path to Library */
const void *l_ld; /* Pointer to .dynamic in memory */
struct link_map *l_next, *l_prev; /* linked list of of mapped libs */
};
int __attribute__((weak))
dlinfo(void *handle, int request, void *p)
{
PERR("dlinfo: Local function called");
return 0;
}
/**
* dlsym
*/
#define RTLD_DEFAULT ((void *)-2)
void __attribute__((weak))
*dlsym(void *handle, const char *name)
{
PERR("dlsym: Local function called");
return 0;
}
} /* extern "C" */
#endif /* _DL_INTERFACE_H_ */

View File

@ -0,0 +1,54 @@
/**
* \brief Dummy functions
* \author Sebastian Sumpf
* \date 2013-12-06
*/
/*
* Copyright (C) 2013-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/printf.h>
extern "C" {
enum {
SHOW_DUMMY = 1,
};
#define DUMMY(retval, name) \
int name(void) { \
if (SHOW_DUMMY) \
PDBG(#name " called (from %p) not implemented", __builtin_return_address(0)); \
return retval; \
}
#define DUMMY_RET(retval, name) \
int name(void) { \
return retval; \
}
DUMMY(-1, rumpuser_anonmmap)
DUMMY(-1, rumpuser_close)
DUMMY(-1, rumpuser_daemonize_begin)
DUMMY(-1, rumpuser_daemonize_done)
DUMMY(-1, rumpuser_dprintf)
DUMMY(-1, rumpuser_exit)
DUMMY(-1, rumpuser_iovread)
DUMMY(-1, rumpuser_iovwrite)
DUMMY(-1, rumpuser_kill)
DUMMY(-1, rumpuser_sp_anonmmap)
DUMMY(-1, rumpuser_sp_copyin)
DUMMY(-1, rumpuser_sp_copyinstr)
DUMMY(-1, rumpuser_sp_copyout)
DUMMY(-1, rumpuser_sp_copyoutstr)
DUMMY(-1, rumpuser_sp_fini)
DUMMY(-1, rumpuser_sp_init)
DUMMY(-1, rumpuser_sp_raise)
DUMMY(-1, rumpuser_thread_exit)
DUMMY(-1, rumpuser_thread_join)
DUMMY(-1, rumpuser_unmap)
} /* extern "C" */

View File

@ -0,0 +1,293 @@
/**
* \brief Rump hypercall-interface implementation
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2013-12-06
*/
/*
* Copyright (C) 2013-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include "sched.h"
#include <base/env.h>
#include <base/printf.h>
#include <base/sleep.h>
#include <os/timed_semaphore.h>
#include <util/allocator_fap.h>
#include <util/string.h>
extern "C" void wait_for_continue();
enum { SUPPORTED_RUMP_VERSION = 17 };
static bool verbose = false;
/* upcalls to rump kernel */
struct rumpuser_hyperup _rump_upcalls;
/********************
** Initialization **
********************/
int rumpuser_init(int version, const struct rumpuser_hyperup *hyp)
{
PDBG("RUMP ver: %d", version);
if (version != SUPPORTED_RUMP_VERSION) {
PERR("Unsupported rump-kernel version (%d) - supported is %d)",
version, SUPPORTED_RUMP_VERSION);
return -1;
}
_rump_upcalls = *hyp;
/*
* Start 'Timeout_thread' so it does not get constructed concurrently (which
* causes one thread to spin in cxa_guard_aqcuire), making emulation *really*
* slow
*/
Genode::Timeout_thread::alarm_timer();
return 0;
}
/*************
** Threads **
*************/
static Hard_context _main_thread("main thread", 0, 0, 0, false);
static Hard_context *myself()
{
Hard_context *h = dynamic_cast<Hard_context *>(Genode::Thread_base::myself());
return h ? h : &_main_thread;
}
Timer::Connection *Hard_context::timer()
{
static Timer::Connection _timer;
return &_timer;
}
void rumpuser_curlwpop(int enum_rumplwpop, struct lwp *l)
{
Hard_context *h = myself();
switch (enum_rumplwpop) {
case RUMPUSER_LWP_CREATE:
case RUMPUSER_LWP_DESTROY:
break;
case RUMPUSER_LWP_SET:
h->set_lwp(l);
break;
case RUMPUSER_LWP_CLEAR:
h->set_lwp(0);
break;
}
}
struct lwp * rumpuser_curlwp(void)
{
return myself()->get_lwp();
}
int rumpuser_thread_create(func f, void *arg, const char *name,
int mustjoin, int priority, int cpui_dx, void **cookie)
{
static int count = 0;
if (mustjoin)
*cookie = (void *)++count;
new (Genode::env()->heap()) Hard_context(name, f, arg, mustjoin ? count : 0);
return 0;
}
int errno;
void rumpuser_seterrno(int e) { errno = e; }
/*************************
** Parameter retrieval **
*************************/
int rumpuser_getparam(const char *name, void *buf, size_t buflen)
{
/* support one cpu */
PDBG("%s", name);
if (!Genode::strcmp(name, "_RUMPUSER_NCPU")) {
Genode::strncpy((char *)buf, "1", 2);
return 0;
}
/* return out cool host name */
if (!Genode::strcmp(name, "_RUMPUSER_HOSTNAME")) {
Genode::strncpy((char *)buf, "rump4genode", 12);
return 0;
}
if (!Genode::strcmp(name, "RUMP_MEMLIMIT")) {
/* leave 2 MB for the Genode */
size_t rump_ram = Genode::env()->ram_session()->avail() - (2 * 1024 * 1024);
/* convert to string */
Genode::snprintf((char *)buf, buflen, "%zu", rump_ram);
PINF("Asserting rump kernel %zu KB of RAM", rump_ram / 1024);
return 0;
}
return -1;
}
/*************
** Console **
*************/
void rumpuser_putchar(int ch)
{
static unsigned char buf[256];
static int count = 0;
buf[count++] = (unsigned char)ch;
if (ch == '\n') {
buf[count] = 0;
int nlocks;
if (myself() != &_main_thread)
rumpkern_unsched(&nlocks, 0);
PLOG("rump: %s", buf);
if (myself() != &_main_thread)
rumpkern_sched(nlocks, 0);
count = 0;
}
}
/************
** Memory **
************/
struct Allocator_policy
{
static int block()
{
int nlocks;
if (myself() != &_main_thread)
rumpkern_unsched(&nlocks, 0);
return nlocks;
}
static void unblock(int nlocks)
{
if (myself() != &_main_thread)
rumpkern_sched(nlocks, 0);
}
};
typedef Allocator::Fap<128 * 1024 * 1024, Allocator_policy> Rump_alloc;
static Genode::Lock _alloc_lock;
static Rump_alloc* allocator()
{
static Rump_alloc _fap(true);
return &_fap;
}
int rumpuser_malloc(size_t len, int alignment, void **memp)
{
Genode::Lock::Guard guard(_alloc_lock);
int align = Genode::log2(alignment);
*memp = allocator()->alloc(len, align);
if (verbose)
PWRN("ALLOC: p: %p, s: %zx, a: %d", *memp, len, align);
return *memp ? 0 : -1;
}
void rumpuser_free(void *mem, size_t len)
{
Genode::Lock::Guard guard(_alloc_lock);
allocator()->free(mem, len);
if (verbose)
PWRN("FREE: p: %p, s: %zx", mem, len);
}
/************
** Clocks **
************/
int rumpuser_clock_gettime(int enum_rumpclock, int64_t *sec, long *nsec)
{
Hard_context *h = myself();
unsigned long t = h->timer()->elapsed_ms();
*sec = (int64_t)t / 1000;
*nsec = (t % 1000) * 1000;
return 0;
}
int rumpuser_clock_sleep(int enum_rumpclock, int64_t sec, long nsec)
{
int nlocks;
unsigned int msec = 0;
Timer::Connection *timer = myself()->timer();
rumpkern_unsched(&nlocks, 0);
switch (enum_rumpclock) {
case RUMPUSER_CLOCK_RELWALL:
msec = sec * 1000 + nsec / (1000*1000UL);
break;
case RUMPUSER_CLOCK_ABSMONO:
msec = timer->elapsed_ms();
msec = ((sec * 1000) + (nsec / (1000 * 1000))) - msec;
break;
}
timer->msleep(msec);
rumpkern_sched(nlocks, 0);
return 0;
}
/*****************
** Random pool **
*****************/
int rumpuser_getrandom(void *buf, size_t buflen, int flags, size_t *retp)
{
Timer::Connection *timer = myself()->timer();
uint8_t *rndbuf;
for (*retp = 0, rndbuf = (uint8_t *)buf; *retp < buflen; (*retp)++) {
*rndbuf++ = timer->elapsed_ms() & 0xff;
timer->msleep(timer->elapsed_ms() & 0xf);
}
return 0;
}

342
dde_rump/src/lib/rump/io.cc Normal file
View File

@ -0,0 +1,342 @@
/**
* \brief Connect rump kernel Genode's block interface
* \author Sebastian Sumpf
* \date 2013-12-16
*/
/*
* Copyright (C) 2013-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include "sched.h"
#include <base/allocator_avl.h>
#include <base/thread.h>
#include <block_session/connection.h>
#include <rump_fs/fs.h>
#include <util/list.h>
#include <util/string.h>
static const bool verbose = false;
enum { GENODE_FD = 64 };
struct Packet : Genode::List<Packet>::Element
{
Block::sector_t blk;
Genode::size_t cnt;
Block::Packet_descriptor::Opcode opcode;
void *data;
long offset;
rump_biodone_fn biodone;
void *donearg;
bool valid;
bool pending;
bool sync;
};
class Backend : public Hard_context
{
private:
enum { COUNT = Block::Session::TX_QUEUE_SIZE };
Genode::Allocator_avl _alloc;
Block::Connection _session;
Genode::size_t _blk_size; /* block size of the device */
Block::sector_t _blk_cnt; /* number of blocks of device */
Block::Session::Operations _blk_ops;
Packet _p[COUNT];
Genode::Semaphore _alloc_sem;
Genode::Semaphore _packet_sem;
int _index_thread = 0;
int _index_client = 0;
Genode::Lock _alloc_lock;
bool _handle;
Genode::Signal_receiver _receiver;
Genode::Signal_dispatcher<Backend> _disp_ack;
Genode::Signal_dispatcher<Backend> _disp_submit;
Genode::List<Packet> *_pending()
{
static Genode::List<Packet> _p;
return &_p;
}
bool _have_pending()
{
return !!_pending()->first();
}
Packet *_find(Block::Packet_descriptor &packet)
{
Packet *p = _pending()->first();
while (p) {
if (p->offset == packet.offset())
return p;
p = p->next();
}
PERR("Pending packet not found");
return 0;
}
Packet *_dequeue()
{
int idx;
for (int i = 0; i < COUNT; i++) {
idx = (_index_thread + i) % COUNT;
if (_p[idx].valid && !_p[idx].pending) {
_index_thread = idx;
_p[idx].pending = true;
return &_p[idx];
}
}
PWRN("Dequeue returned 0");
return 0;
}
void _free(Packet *p)
{
p->valid = false;
p->pending = false;
_alloc_sem.up();
}
void _ready_to_submit(unsigned) { _handle = false; }
void _ack_avail(unsigned)
{
_handle = false;
while (_session.tx()->ack_avail()) {
Block::Packet_descriptor packet = _session.tx()->get_acked_packet();
Packet *p = _find(packet);
if (p->opcode == Block::Packet_descriptor::READ)
Genode::memcpy(p->data, _session.tx()->packet_content(packet),
packet.block_count() * _blk_size);
/* sync session if requested */
if (p->sync)
_session.sync();
int dummy;
if (verbose)
PDBG("BIO done p: %p bio %p", p, p->donearg);
rumpkern_sched(0, 0);
if (p->biodone)
p->biodone(p->donearg, p->cnt * _blk_size,
packet.succeeded() ? 0 : EIO);
rumpkern_unsched(&dummy, 0);
_session.tx()->release_packet(packet);
_pending()->remove(p);
_free(p);
}
}
void _handle_signal()
{
_handle = true;
while (_handle) {
Genode::Signal s = _receiver.wait_for_signal();
static_cast<Genode::Signal_dispatcher_base *>
(s.context())->dispatch(s.num());
}
}
protected:
void entry()
{
_rump_upcalls.hyp_schedule();
_rump_upcalls.hyp_lwproc_newlwp(0);
_rump_upcalls.hyp_unschedule();
while (true) {
while (_packet_sem.cnt() <= 0 && _have_pending())
_handle_signal();
_packet_sem.down();
while (!_session.tx()->ready_to_submit())
_handle_signal();
Packet *p = _dequeue();
/* zero or sync request */
if (!p->cnt) {
if (p->sync)
_session.sync();
_free(p);
continue;
}
for (bool done = false; !done;)
try {
Block::Packet_descriptor packet(
_session.dma_alloc_packet(p->cnt * _blk_size),
p->opcode, p->blk, p->cnt);
/* got packet copy data */
if (p->opcode == Block::Packet_descriptor::WRITE)
Genode::memcpy(_session.tx()->packet_content(packet),
p->data, p->cnt * _blk_size);
_session.tx()->submit_packet(packet);
/* mark as pending */
p->offset = packet.offset();
_pending()->insert(p);
done = true;
} catch(Block::Session::Tx::Source::Packet_alloc_failed) {
_handle_signal();
}
}
}
public:
Backend()
: Hard_context("block_io", 0, 0, 0, false),
_alloc(Genode::env()->heap()),
_session(&_alloc),
_alloc_sem(COUNT),
_disp_ack(_receiver, *this, &Backend::_ack_avail),
_disp_submit(_receiver, *this, &Backend::_ready_to_submit)
{
_session.tx_channel()->sigh_ack_avail(_disp_ack);
_session.tx_channel()->sigh_ready_to_submit(_disp_submit);
_session.info(&_blk_cnt, &_blk_size, &_blk_ops);
PDBG("Backend blk_size %zu", _blk_size);
Genode::memset(_p, 0, sizeof(_p));
start();
}
uint64_t block_count() const { return (uint64_t)_blk_cnt; }
size_t block_size() const { return (size_t)_blk_size; }
bool writable()
{
return _blk_ops.supported(Block::Packet_descriptor::WRITE);
}
Packet *alloc()
{
int idx;
_alloc_sem.down();
Genode::Lock::Guard guard(_alloc_lock);
for (int i = 0; i < COUNT; i++) {
idx = (_index_client + i) % COUNT;
if (!_p[idx].valid) {
_p[idx].valid = true;
_p[idx].pending = false;
_index_client = idx;
return &_p[idx];
}
}
PWRN("Alloc returned 0");
return 0;
}
void submit() { _packet_sem.up(); }
};
static Backend *backend()
{
static Backend *_b = 0;
if (_b)
return _b;
try {
int nlocks;
rumpkern_unsched(&nlocks, 0);
_b = new(Genode::env()->heap())Backend();
rumpkern_sched(nlocks, 0);
} catch (Genode::Parent::Service_denied) {
PERR("Opening block session denied!");
}
return _b;
}
int rumpuser_getfileinfo(const char *name, uint64_t *size, int *type)
{
if (Genode::strcmp(GENODE_BLOCK_SESSION, name))
return ENXIO;
if (type)
*type = RUMPUSER_FT_BLK;
if (size)
*size = backend()->block_count() * backend()->block_size();
return 0;
}
int rumpuser_open(const char *name, int mode, int *fdp)
{
if (!(mode & RUMPUSER_OPEN_BIO || Genode::strcmp(GENODE_BLOCK_SESSION, name)))
return ENXIO;
/* check for writable */
if ((mode & RUMPUSER_OPEN_ACCMODE) && !backend()->writable())
return EROFS;
*fdp = GENODE_FD;
return 0;
}
void rumpuser_bio(int fd, int op, void *data, size_t dlen, int64_t off,
rump_biodone_fn biodone, void *donearg)
{
int nlocks;
rumpkern_unsched(&nlocks, 0);
Packet *p = backend()->alloc();
#if 0
PDBG("fd: %d op: %d len: %zu off: %lx p %p bio %p sync %u", fd, op, dlen, off,
p, donearg, !!(op & RUMPUSER_BIO_SYNC));
#endif
p->opcode= op & RUMPUSER_BIO_WRITE ? Block::Packet_descriptor::WRITE :
Block::Packet_descriptor::READ;
p->cnt = dlen / backend()->block_size();
p->blk = off / backend()->block_size();
p->data = data;
p->biodone = biodone;
p->donearg = donearg;
p->sync = !!(op & RUMPUSER_BIO_SYNC);
backend()->submit();
rumpkern_sched(nlocks, 0);
}
void rump_io_backend_sync()
{
/* send empty packet with sync request */
Packet *p = backend()->alloc();
p->cnt = 0;
p->sync = true;
backend()->submit();
}

View File

@ -0,0 +1,43 @@
/**
* \brief Rump-scheduling upcalls
* \author Sebastian Sump
* \date 2013-12-06
*/
/*
* Copyright (C) 2013-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SCHED_H_
#define _SCHED_H_
extern "C" {
#include <sys/cdefs.h>
#include <sys/types.h>
#include <rump/rump.h>
#include <rump/rumpuser.h>
#include <sys/errno.h>
}
#include <util/hard_context.h>
/* upcalls to rump kernel */
extern struct rumpuser_hyperup _rump_upcalls;
static inline void
rumpkern_unsched(int *nlocks, void *interlock)
{
_rump_upcalls.hyp_backend_unschedule(0, nlocks, interlock);
}
static inline void
rumpkern_sched(int nlocks, void *interlock)
{
_rump_upcalls.hyp_backend_schedule(nlocks, interlock);
}
#endif /* _SCHED_H_ */

View File

@ -0,0 +1,503 @@
/**
* \brief Rump-synchronization primitives
* \author Sebastian Sumpf
* \author Christian Prochaska (conditional variables)
* \date 2014-01-13
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
extern "C" {
#include <sys/cdefs.h>
}
#include <os/timed_semaphore.h>
#include "sched.h"
/*************
** Mutexes **
*************/
struct rumpuser_mtx
{
Genode::Semaphore sem;
Genode::Lock counter_lock;
struct lwp *owner;
int flags;
rumpuser_mtx(int flags) : sem(1), owner(0), flags(flags) { }
bool down(bool try_lock = false)
{
counter_lock.lock();
if (sem.cnt() > 1)
PERR("SEM cnt > 1");
bool locked = sem.cnt() <= 0;
counter_lock.unlock();
if (locked && try_lock)
return false;
sem.down();
set_owner();
return true;
}
void up()
{
Genode::Lock::Guard guard(counter_lock);
clear_owner();
sem.up();
}
bool try_lock()
{
return down(true);
}
void set_owner()
{
if (flags & RUMPUSER_MTX_KMUTEX) {
if(owner != 0) {
PERR("OWNER != 0 %d", sem.cnt());
}
owner = rumpuser_curlwp();
}
}
void clear_owner()
{
if (flags & RUMPUSER_MTX_KMUTEX) {
if(owner == 0) {
PERR("OWNER 0");
}
owner = 0;
}
}
};
void rumpuser_mutex_init(struct rumpuser_mtx **mtxp, int flags)
{
*mtxp = new(Genode::env()->heap()) rumpuser_mtx(flags);
}
void rumpuser_mutex_owner(struct rumpuser_mtx *mtx, struct lwp **lp)
{
*lp = mtx->owner;
}
void rumpuser_mutex_enter_nowrap(struct rumpuser_mtx *mtx)
{
mtx->down();
}
void rumpuser_mutex_enter(struct rumpuser_mtx *mtx)
{
if (mtx->flags & RUMPUSER_MTX_SPIN) {
rumpuser_mutex_enter_nowrap(mtx);
return;
}
if (!mtx->try_lock()) {
int nlocks;
rumpkern_unsched(&nlocks, 0);
mtx->down();
rumpkern_sched(nlocks, 0);
}
}
int rumpuser_mutex_tryenter(struct rumpuser_mtx *mtx)
{
return mtx->try_lock() ? 0 : 1;
}
void rumpuser_mutex_exit(struct rumpuser_mtx *mtx)
{
mtx->up();
}
void rumpuser_mutex_destroy(struct rumpuser_mtx *mtx)
{
destroy(Genode::env()->heap(), mtx);
}
/***************************
** Conditional variables **
***************************/
struct timespec {
long tv_sec; /* seconds */
long tv_nsec;/* nanoseconds */
};
static unsigned long timespec_to_ms(const struct timespec ts)
{
return (ts.tv_sec * 1000) + (ts.tv_nsec / (1000 * 1000));
}
struct Cond
{
int num_waiters;
int num_signallers;
Genode::Lock counter_lock;
Genode::Timed_semaphore signal_sem;
Genode::Semaphore handshake_sem;
Cond() : num_waiters(0), num_signallers(0) { }
int timedwait(struct rumpuser_mtx *mutex,
const struct timespec *abstime)
{
using namespace Genode;
int result = 0;
Alarm::Time timeout = 0;
counter_lock.lock();
num_waiters++;
counter_lock.unlock();
mutex->up();
if (!abstime)
signal_sem.down();
else {
struct timespec currtime;
rumpuser_clock_gettime(0, (int64_t *)&currtime.tv_sec, &currtime.tv_nsec);
unsigned long abstime_ms = timespec_to_ms(*abstime);
unsigned long currtime_ms = timespec_to_ms(currtime);
if (abstime_ms > currtime_ms)
timeout = abstime_ms - currtime_ms;
try {
signal_sem.down(timeout);
} catch (Timeout_exception) {
result = -2;
}
catch (Nonblocking_exception) {
result = 0;
}
}
counter_lock.lock();
if (num_signallers > 0) {
if (result == -2) /* timeout occured */
signal_sem.down();
handshake_sem.up();
--num_signallers;
}
num_waiters--;
counter_lock.unlock();
mutex->down();
return result == -2 ? ETIMEDOUT : 0;
}
int wait(struct rumpuser_mtx *mutex)
{
return timedwait(mutex, 0);
}
int signal()
{
counter_lock.lock();
if (num_waiters > num_signallers) {
++num_signallers;
signal_sem.up();
counter_lock.unlock();
handshake_sem.down();
} else
counter_lock.unlock();
return 0;
}
int broadcast()
{
counter_lock.lock();
if (num_waiters > num_signallers) {
int still_waiting = num_waiters - num_signallers;
num_signallers = num_waiters;
for (int i = 0; i < still_waiting; i++)
signal_sem.up();
counter_lock.unlock();
for (int i = 0; i < still_waiting; i++)
handshake_sem.down();
} else
counter_lock.unlock();
return 0;
}
};
struct rumpuser_cv {
Cond cond;
};
void rumpuser_cv_init(struct rumpuser_cv **cv)
{
*cv = new(Genode::env()->heap()) rumpuser_cv();
}
void rumpuser_cv_destroy(struct rumpuser_cv *cv)
{
destroy(Genode::env()->heap(), cv);
}
static void cv_unschedule(struct rumpuser_mtx *mtx, int *nlocks)
{
rumpkern_unsched(nlocks, mtx);
}
static void cv_reschedule(struct rumpuser_mtx *mtx, int nlocks)
{
/*
* If the cv interlock is a spin mutex, we must first release
* the mutex that was reacquired by _pth_cond_wait(),
* acquire the CPU context and only then relock the mutex.
* This is to preserve resource allocation order so that
* we don't deadlock. Non-spinning mutexes don't have this
* problem since they don't use a hold-and-wait approach
* to acquiring the mutex wrt the rump kernel CPU context.
*
* The more optimal solution would be to rework rumpkern_sched()
* so that it's possible to tell the scheduler
* "if you need to block, drop this lock first", but I'm not
* going poking there without some numbers on how often this
* path is taken for spin mutexes.
*/
if ((mtx->flags & (RUMPUSER_MTX_SPIN | RUMPUSER_MTX_KMUTEX)) ==
(RUMPUSER_MTX_SPIN | RUMPUSER_MTX_KMUTEX)) {
mtx->up();
rumpkern_sched(nlocks, mtx);
rumpuser_mutex_enter_nowrap(mtx);
} else {
rumpkern_sched(nlocks, mtx);
}
}
void rumpuser_cv_wait(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx)
{
int nlocks;
cv_unschedule(mtx, &nlocks);
cv->cond.wait(mtx);
cv_reschedule(mtx, nlocks);
}
void rumpuser_cv_wait_nowrap(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx)
{
cv->cond.wait(mtx);
}
int rumpuser_cv_timedwait(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx,
int64_t sec, int64_t nsec)
{
struct timespec ts;
int rv, nlocks;
/*
* Get clock already here, just in case we will be put to sleep
* after releasing the kernel context.
*
* The condition variables should use CLOCK_MONOTONIC, but since
* that's not available everywhere, leave it for another day.
*/
rumpuser_clock_gettime(0, (int64_t *)&ts.tv_sec, &ts.tv_nsec);
cv_unschedule(mtx, &nlocks);
ts.tv_sec += sec;
ts.tv_nsec += nsec;
if (ts.tv_nsec >= 1000*1000*1000) {
ts.tv_sec++;
ts.tv_nsec -= 1000*1000*1000;
}
rv = cv->cond.timedwait(mtx, &ts);
cv_reschedule(mtx, nlocks);
return rv;
}
void rumpuser_cv_signal(struct rumpuser_cv *cv)
{
cv->cond.signal();
}
void rumpuser_cv_broadcast(struct rumpuser_cv *cv)
{
cv->cond.broadcast();
}
void rumpuser_cv_has_waiters(struct rumpuser_cv *cv, int *nwaiters)
{
*nwaiters = cv->cond.num_waiters;
}
/*********************
** Read/write lock **
*********************/
struct Rw_lock {
Genode::Semaphore _lock;
Genode::Lock _inc;
Genode::Lock _write;
int _read;
Rw_lock() : _lock(1), _read(0) {}
bool read_lock(bool try_lock)
{
Genode::Lock::Guard guard(_inc);
if (_read > 0) {
_read++;
return true;
}
bool locked = lock(true);
if (locked) {
_read = 1;
return true;
}
if (try_lock)
return false;
lock(false);
_read = 1;
return true;
}
void read_unlock()
{
Genode::Lock::Guard guard(_inc);
if (--_read == 0)
unlock();
}
bool lock(bool try_lock)
{
Genode::Lock::Guard guard(_write);
if (_lock.cnt() > 0) {
_lock.down();
return true;
}
if (try_lock)
return false;
_lock.down();
return true;
}
void unlock()
{
Genode::Lock::Guard guard(_write);
_lock.up();
}
int readers() { return _read; }
int writer() { return (_lock.cnt() <= 0 && !_read) ? 1 : 0; }
};
struct rumpuser_rw
{
Rw_lock rw;
};
void rumpuser_rw_init(struct rumpuser_rw **rw)
{
*rw = new(Genode::env()->heap()) rumpuser_rw();
}
void rumpuser_rw_enter(int enum_rumprwlock, struct rumpuser_rw *rw)
{
if (enum_rumprwlock == RUMPUSER_RW_WRITER)
rw->rw.lock(false);
else
rw->rw.read_lock(false);
}
int rumpuser_rw_tryenter(int enum_rumprwlock, struct rumpuser_rw *rw)
{
bool locked = enum_rumprwlock == RUMPUSER_RW_WRITER ?
rw->rw.lock(true) : rw->rw.read_lock(true);
return locked ? 0 : 1;
}
int rumpuser_rw_tryupgrade(struct rumpuser_rw *rw)
{
return 1;
}
void rumpuser_rw_downgrade(struct rumpuser_rw *rw)
{
}
void rumpuser_rw_exit(struct rumpuser_rw *rw)
{
if (rw->rw.readers())
rw->rw.read_unlock();
else
rw->rw.unlock();
}
void rumpuser_rw_held(int enum_rumprwlock, struct rumpuser_rw *rw, int *rv)
{
*rv = enum_rumprwlock == RUMPUSER_RW_WRITER ? rw->rw.writer() :
rw->rw.readers();
}
void rumpuser_rw_destroy(struct rumpuser_rw *rw)
{
destroy(Genode::env()->heap(), rw);
}

View File

@ -0,0 +1,32 @@
/*
* \brief Additonial sections required by all rump libraries
*
* Modified version of original linker script
*
* \author Sebastiasn Sumpf
* \date 2013-12-12
*/
SECTIONS
{
.rump_modules :
{
__start_link_set_modules = .;
KEEP(*(link_set_modules));
__stop_link_set_modules = .;
} : rw
.rump_domains :
{
__start_link_set_domains = .;
KEEP(*(link_set_domains));
__stop_link_set_domains = .;
} : rw
.rump_components :
{
__start_link_set_rump_components = .;
KEEP(*(link_set_rump_components));
__stop_link_set_rump_components = .;
} : rw
}

View File

@ -0,0 +1,254 @@
/**
* \brief File-system directory node
* \author Norman Feske
* \author Christian Helmuth
* \author Sebastian Sumpf
* \date 2013-11-11
*/
/*
* Copyright (C) 2013-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _DIRECTORY_H_
#define _DIRECTORY_H_
/* Genode include */
#include <os/path.h>
/* local includes */
#include "node.h"
#include "util.h"
#include "file.h"
#include "symlink.h"
namespace File_system {
class Directory;
}
class File_system::Directory : public Node
{
private:
enum { BUFFER_SIZE = 4096 };
typedef Genode::Path<MAX_PATH_LEN> Path;
int _fd;
Path _path;
Allocator &_alloc;
unsigned long _inode(char const *path, bool create)
{
int ret;
if (create) {
mode_t ugo = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
ret = rump_sys_mkdir(path, ugo);
if (ret == -1)
throw No_space();
}
struct stat s;
ret = rump_sys_lstat(path, &s);
if (ret == -1)
throw Lookup_failed();
return s.st_ino;
}
int _open(char const *path)
{
struct stat s;
int ret = rump_sys_lstat(path, &s);
if (ret == -1 || !S_ISDIR(s.st_mode))
throw Lookup_failed();
int fd = rump_sys_open(path, O_RDONLY);
if (fd == -1)
throw Lookup_failed();
return fd;
}
static char *_buffer()
{
/* buffer for directory entries */
static char buf[BUFFER_SIZE];
return buf;
}
public:
Directory(Allocator &alloc, char const *path, bool create)
:
Node(_inode(path, create)),
_fd(_open(path)),
_path(path, "./"),
_alloc(alloc)
{
Node::name(basename(path));
}
virtual ~Directory()
{
rump_sys_close(_fd);
}
File * file(char const *name, Mode mode, bool create)
{
return new (&_alloc) File(_fd, name, mode, create);
}
Symlink * symlink(char const *name, bool create)
{
return new (&_alloc) Symlink(_path.base(), name, create);
}
Directory * subdir(char const *path, bool create)
{
Path dir_path(path, _path.base());
Directory *dir = new (&_alloc) Directory(_alloc, dir_path.base(), create);
return dir;
}
Node * node(char const *path)
{
Path node_path(path, _path.base());
struct stat s;
int ret = rump_sys_lstat(node_path.base(), &s);
if (ret == -1)
throw Lookup_failed();
Node *node = 0;
if (S_ISDIR(s.st_mode))
node = new (&_alloc) Directory(_alloc, node_path.base(), false);
else if (S_ISREG(s.st_mode))
node = new (&_alloc) File(node_path.base(), STAT_ONLY);
else if (S_ISLNK(s.st_mode))
node = new (&_alloc)Symlink(node_path.base());
else
throw Lookup_failed();
return node;
}
size_t read(char *dst, size_t len, seek_off_t seek_offset)
{
if (len < sizeof(Directory_entry)) {
PERR("read buffer too small for directory entry");
return 0;
}
if (seek_offset % sizeof(Directory_entry)) {
PERR("seek offset not aligned to sizeof(Directory_entry)");
return 0;
}
seek_off_t index = seek_offset / sizeof(Directory_entry);
int bytes;
rump_sys_lseek(_fd, 0, SEEK_SET);
struct dirent *dent = 0;
seek_off_t i = 0;
char *buf = _buffer();
do {
bytes = rump_sys_getdents(_fd, buf, BUFFER_SIZE);
void *current, *end;
for (current = buf, end = &buf[bytes];
current < end;
current = _DIRENT_NEXT((dirent *)current), i++)
if (i == index) {
dent = (dirent *)current;
break;
}
} while(bytes && !dent);
if (!dent)
return 0;
/*
* Build absolute path, this becomes necessary as our 'Path' class strips
* trailing dots, which will not work for '.' and '..' directories.
*/
size_t base_len = strlen(_path.base());
char path[dent->d_namlen + base_len + 2];
memcpy(path, _path.base(), base_len);
path[base_len] = '/';
strncpy(path + base_len + 1, dent->d_name, dent->d_namlen + 1);
/*
* We cannot use 'd_type' member of 'dirent' here since the EXT2
* implementation sets the type to unkown. Hence we use stat.
*/
struct stat s;
rump_sys_lstat(path, &s);
Directory_entry *e = (Directory_entry *)(dst);
if (S_ISDIR(s.st_mode))
e->type = Directory_entry::TYPE_DIRECTORY;
else if (S_ISREG(s.st_mode))
e->type = Directory_entry::TYPE_FILE;
else if (S_ISLNK(s.st_mode))
e->type = Directory_entry::TYPE_SYMLINK;
else
return 0;
strncpy(e->name, dent->d_name, dent->d_namlen + 1);
return sizeof(Directory_entry);
}
size_t write(char const *src, size_t len, seek_off_t seek_offset)
{
/* writing to directory nodes is not supported */
return 0;
}
size_t num_entries() const
{
int bytes = 0;
int count = 0;
rump_sys_lseek(_fd, 0, SEEK_SET);
char *buf = _buffer();
do {
bytes = rump_sys_getdents(_fd, buf, BUFFER_SIZE);
void *current, *end;
for (current = buf, end = &buf[bytes];
current < end;
current = _DIRENT_NEXT((dirent *)current), count++) { }
} while(bytes);
return count;
}
void unlink(char const *path)
{
Path node_path(path, _path.base());
struct stat s;
int ret = rump_sys_lstat(node_path.base(), &s);
if (ret == -1)
throw Lookup_failed();
if (S_ISDIR(s.st_mode))
ret = rump_sys_rmdir(node_path.base());
else if (S_ISREG(s.st_mode) || S_ISLNK(s.st_mode))
ret = rump_sys_unlink(node_path.base());
else
throw Lookup_failed();
if (ret == -1)
PERR("Error during unlink of %s", node_path.base());
}
};
#endif /* _DIRECTORY_H_ */

View File

@ -0,0 +1,154 @@
/**
* \brief File node
* \author Norman Feske
* \author Christian Helmuth
* \auhtor Sebastian Sumpf
* \date 2013-11-11
*/
/*
* Copyright (C) 2013-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _FILE_H_
#define _FILE_H_
#include "node.h"
#include "util.h"
namespace File_system {
class File;
}
class File_system::File : public Node
{
private:
int _fd;
int _access_mode(Mode const &mode)
{
switch (mode) {
case STAT_ONLY:
case READ_ONLY: return O_RDONLY;
case WRITE_ONLY: return O_WRONLY;
case READ_WRITE: return O_RDWR;
default: return O_RDONLY;
}
}
unsigned long _inode(int dir, char const *name, bool create)
{
int ret;
if (create) {
mode_t ugo = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
ret = rump_sys_mknodat(dir, name, S_IFREG | ugo, 0);
if (ret == -1 && errno != EEXIST)
throw No_space();
}
struct stat s;
ret = rump_sys_fstatat(dir, name, &s, 0);
if (ret == -1)
throw Lookup_failed();
return s.st_ino;
}
unsigned long _inode_path(char const *path)
{
int ret;
struct stat s;
ret = rump_sys_stat(path, &s);
if (ret == -1)
throw Lookup_failed();
return s.st_ino;
}
int _open(int dir, char const *name, Mode mode)
{
int fd = rump_sys_openat(dir, name, _access_mode(mode));
if (fd == -1)
throw Lookup_failed();
return fd;
}
int _open_path(char const *path, Mode mode)
{
int fd = rump_sys_open(path, _access_mode(mode));
if (fd == -1)
throw Lookup_failed();
return fd;
}
public:
File(int dir,
char const *name,
Mode mode,
bool create)
: Node(_inode(dir, name, create)),
_fd(_open(dir, name, mode))
{
Node::name(name);
}
File(char const *path, Mode mode)
:
Node(_inode_path(path)),
_fd(_open_path(path, mode))
{
Node::name(basename(path));
}
virtual ~File() { rump_sys_close(_fd); }
size_t read(char *dst, size_t len, seek_off_t seek_offset)
{
ssize_t ret = rump_sys_pread(_fd, dst, len, seek_offset);
return ret == -1 ? 0 : ret;
}
size_t write(char const *src, size_t len, seek_off_t seek_offset)
{
/* should we append? */
if (seek_offset == ~0ULL) {
off_t off = rump_sys_lseek(_fd, 0, SEEK_END);
if (off == -1)
return 0;
seek_offset = off;
}
ssize_t ret = rump_sys_pwrite(_fd, src, len, seek_offset);
return ret == -1 ? 0 : ret;
}
file_size_t length() const
{
struct stat s;
if(rump_sys_fstat(_fd, &s) < 0)
return 0;
return s.st_size;
}
void truncate(file_size_t size)
{
rump_sys_ftruncate(_fd, size);
mark_as_updated();
}
};
#endif /* _FILE_H_ */

View File

@ -0,0 +1,171 @@
/*
* \brief Rump initialization
* \author Sebastian Sumpf
* \date 2014-01-17
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include "file_system.h"
#include <base/thread.h>
#include <os/config.h>
#include <rump_fs/fs.h>
#include <timer_session/connection.h>
#include <util/string.h>
#include <util/hard_context.h>
/**
* We define our own fs arg structure to fit all sizes, we assume that 'fspec'
* is the only valid argument and all other fields are unused.
*/
struct fs_args
{
char *fspec;
char pad[150];
fs_args() { Genode::memset(pad, 0, sizeof(pad)); }
};
namespace File_system {
class Sync;
};
static char const *fs_types[] = { RUMP_MOUNT_CD9660, RUMP_MOUNT_EXT2FS,
RUMP_MOUNT_FFS, RUMP_MOUNT_MSDOS,
RUMP_MOUNT_NFS, RUMP_MOUNT_NTFS,
RUMP_MOUNT_SMBFS, RUMP_MOUNT_UDF, 0 };
static char _fs_type[10];
static bool _supports_symlinks;
static bool _check_type(char const *type)
{
for (int i = 0; fs_types[i]; i++)
if (!Genode::strcmp(type, fs_types[i]))
return true;
return false;
}
static void _print_types()
{
PERR("fs types:");
for (int i = 0; fs_types[i]; i++)
PERR("\t%s", fs_types[i]);
}
static bool check_symlinks()
{
if (!Genode::strcmp(_fs_type, RUMP_MOUNT_EXT2FS))
return true;
if (!Genode::strcmp(_fs_type, RUMP_MOUNT_FFS))
return true;
return false;
}
static bool check_read_only()
{
if (!Genode::strcmp(_fs_type, RUMP_MOUNT_CD9660))
return true;
return false;
}
class File_system::Sync : public Genode::Thread<1024 * sizeof(Genode::addr_t)>
{
private:
Timer::Connection _timer;
Genode::Signal_rpc_member<Sync> _sync_dispatcher;
void _process_sync(unsigned)
{
/* sync through front-end */
rump_sys_sync();
/* sync Genode back-end */
rump_io_backend_sync();
}
protected:
void entry()
{
while (1) {
_timer.msleep(1000);
/* send sync request, this goes to server entry point thread */
Genode::Signal_transmitter(_sync_dispatcher).submit();
}
}
public:
Sync(Server::Entrypoint &ep)
:
Thread("rump_fs_sync"),
_sync_dispatcher(ep, *this, &Sync::_process_sync)
{
start();
}
};
void File_system::init(Server::Entrypoint &ep)
{
if (!Genode::config()->xml_node().attribute("fs").value(_fs_type, 10) ||
!_check_type(_fs_type)) {
PERR("Invalid or no file system given (use \'<config fs=\"<fs type>\"/>)");
_print_types();
throw Genode::Exception();
}
PINF("Using %s as file system", _fs_type);
/* start rump kernel */
rump_init();
/* register block device */
rump_pub_etfs_register(GENODE_DEVICE, GENODE_BLOCK_SESSION, RUMP_ETFS_BLK);
/* mount into extra-terrestrial-file system */
struct fs_args args;
int opts = check_read_only() ? RUMP_MNT_RDONLY : 0;
args.fspec = (char *)GENODE_DEVICE;
if (rump_sys_mount(_fs_type, "/", opts, &args, sizeof(args)) == -1) {
PERR("Mounting '%s' file system failed (errno %u)", _fs_type, errno);
throw Genode::Exception();
}
/* check support for symlinks */
_supports_symlinks = check_symlinks();
new (Genode::env()->heap()) Sync(ep);
}
bool File_system::supports_symlinks() { return _supports_symlinks; }
/*
* On some platforms we end-up pulling in string.h prototypes
*/
extern "C" void *memcpy(void *d, void *s, size_t n)
{
return Genode::memcpy(d, s, n);
}
extern "C" void *memset(void *s, int c, size_t n)
{
return Genode::memset(s, c, n);
}

View File

@ -0,0 +1,38 @@
/**
* \brief Rump initialization and required header
* \author Sebastian Sumpf
* \date 2014-01-17
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _FILE_SYSTEM_H_
#define _FILE_SYSTEM_H_
extern "C" {
#include <sys/cdefs.h>
#include <sys/errno.h>
#include <fcntl.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h>
#include <rump/rump.h>
#include <rump/rump_syscalls.h>
}
#include <base/signal.h>
#include <os/server.h>
namespace File_system {
void init(Server::Entrypoint &ep);
bool supports_symlinks();
}
extern int errno;
#endif /* _FILE_SYSTEM_H_ */

View File

@ -0,0 +1,456 @@
/**
* \brief RUMP file system interface implementation
* \author Christian Helmuth
* \author Sebastian Sumpf
* \date 2014-01-14
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include "undef.h"
#include <file_system_session/rpc_object.h>
#include <os/server.h>
#include <os/session_policy.h>
#include <root/component.h>
#include <rump_fs/fs.h>
#include "file_system.h"
#include "directory.h"
#include "node_handle_registry.h"
namespace File_system {
struct Main;
struct Root;
struct Session_component;
}
class File_system::Session_component : public Session_rpc_object
{
private:
Allocator &_md_alloc;
Directory &_root;
Node_handle_registry _handle_registry;
bool _writable;
Signal_rpc_member<Session_component> _process_packet_dispatcher;
/******************************
** Packet-stream processing **
******************************/
/**
* Perform packet operation
*
* \return true on success, false on failure
*/
void _process_packet_op(Packet_descriptor &packet, Node &node)
{
void * const content = tx_sink()->packet_content(packet);
size_t const length = packet.length();
seek_off_t const offset = packet.position();
if (!content || (packet.length() > packet.size())) {
packet.succeeded(false);
return;
}
/* resulting length */
size_t res_length = 0;
switch (packet.operation()) {
case Packet_descriptor::READ:
res_length = node.read((char *)content, length, offset);
break;
case Packet_descriptor::WRITE:
res_length = node.write((char const *)content, length, offset);
break;
}
packet.length(res_length);
packet.succeeded(res_length > 0);
}
void _process_packet()
{
Packet_descriptor packet = tx_sink()->get_packet();
/* assume failure by default */
packet.succeeded(false);
try {
Node *node = _handle_registry.lookup(packet.handle());
_process_packet_op(packet, *node);
}
catch (Invalid_handle) { PERR("Invalid_handle"); }
catch (Size_limit_reached) { PERR("Size_limit_reached"); }
/*
* The 'acknowledge_packet' function cannot block because we
* checked for 'ready_to_ack' in '_process_packets'.
*/
tx_sink()->acknowledge_packet(packet);
}
/**
* Called by signal dispatcher, executed in the context of the main
* thread (not serialized with the RPC functions)
*/
void _process_packets(unsigned)
{
while (tx_sink()->packet_avail()) {
/*
* Make sure that the '_process_packet' function does not
* block.
*
* If the acknowledgement queue is full, we defer packet
* processing until the client processed pending
* acknowledgements and thereby emitted a ready-to-ack
* signal. Otherwise, the call of 'acknowledge_packet()'
* in '_process_packet' would infinitely block the context
* of the main thread. The main thread is however needed
* for receiving any subsequent 'ready-to-ack' signals.
*/
if (!tx_sink()->ready_to_ack())
return;
_process_packet();
}
}
/**
* Check if string represents a valid path (must start with '/')
*/
static void _assert_valid_path(char const *path)
{
if (!path || path[0] != '/') {
PWRN("malformed path '%s'", path);
throw Lookup_failed();
}
}
public:
/**
* Constructor
*/
Session_component(size_t tx_buf_size,
Server::Entrypoint &ep,
char const *root_dir,
bool writeable,
Allocator &md_alloc)
:
Session_rpc_object(env()->ram_session()->alloc(tx_buf_size), ep.rpc_ep()),
_md_alloc(md_alloc),
_root(*new (&_md_alloc) Directory(_md_alloc, root_dir, false)),
_writable(writeable),
_process_packet_dispatcher(ep, *this, &Session_component::_process_packets)
{
/*
* Register '_process_packets' dispatch function as signal
* handler for packet-avail and ready-to-ack signals.
*/
_tx.sigh_packet_avail(_process_packet_dispatcher);
_tx.sigh_ready_to_ack(_process_packet_dispatcher);
}
/**
* Destructor
*/
~Session_component()
{
Dataspace_capability ds = tx_sink()->dataspace();
env()->ram_session()->free(static_cap_cast<Ram_dataspace>(ds));
destroy(&_md_alloc, &_root);
}
/***************************
** File_system interface **
***************************/
File_handle file(Dir_handle dir_handle, Name const &name, Mode mode, bool create)
{
if (!valid_name(name.string()))
throw Invalid_name();
Directory *dir = _handle_registry.lookup(dir_handle);
if (!_writable)
if (create || (mode != STAT_ONLY && mode != READ_ONLY))
throw Permission_denied();
File *file = dir->file(name.string(), mode, create);
return _handle_registry.alloc(file);
}
Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create)
{
if (!File_system::supports_symlinks())
return Symlink_handle();
if (!valid_name(name.string()))
throw Invalid_name();
Directory *dir = _handle_registry.lookup(dir_handle);
if (create && !_writable)
throw Permission_denied();
Symlink *link = dir->symlink(name.string(), create);
return _handle_registry.alloc(link);
}
Dir_handle dir(Path const &path, bool create)
{
char const *path_str = path.string();
_assert_valid_path(path_str);
/* skip leading '/' */
path_str++;
if (!_writable && create)
throw Permission_denied();
if (!path.is_valid_string())
throw Name_too_long();
Directory *dir = _root.subdir(path_str, create);
return _handle_registry.alloc(dir);
}
Node_handle node(Path const &path)
{
char const *path_str = path.string();
_assert_valid_path(path_str);
Node *node = _root.node(path_str + 1);
Node_handle h = _handle_registry.alloc(node);
return h;
}
void close(Node_handle handle)
{
Node *node = 0;
try {
node = _handle_registry.lookup(handle);
} catch (Invalid_handle) { return; }
_handle_registry.free(handle);
/* destruct node */
if (node)
destroy(&_md_alloc, node);
}
Status status(Node_handle node_handle)
{
Node *node = _handle_registry.lookup(node_handle);
Status s;
s.inode = node->inode();
s.size = 0;
s.mode = 0;
File *file = dynamic_cast<File *>(node);
if (file) {
s.size = file->length();
s.mode = File_system::Status::MODE_FILE;
return s;
}
Directory *dir = dynamic_cast<Directory *>(node);
if (dir) {
s.size = dir->num_entries()*sizeof(Directory_entry);
s.mode = File_system::Status::MODE_DIRECTORY;
return s;
}
Symlink *link = dynamic_cast<Symlink *>(node);
if (link) {
s.size = link->length();
s.mode = File_system::Status::MODE_SYMLINK;
return s;
}
return Status();
}
void control(Node_handle, Control)
{
PERR("%s not implemented", __func__);
}
void unlink(Dir_handle dir_handle, Name const &name)
{
if (!valid_name(name.string()))
throw Invalid_name();
if (!_writable)
throw Permission_denied();
Directory *dir = _handle_registry.lookup(dir_handle);
dir->unlink(name.string());
}
void truncate(File_handle file_handle, file_size_t size)
{
if (!_writable)
throw Permission_denied();
File *file = _handle_registry.lookup(file_handle);
file->truncate(size);
}
void move(Dir_handle, Name const &, Dir_handle, Name const &)
{
PERR("%s not implemented", __func__);
}
void sigh(Node_handle node_handle, Signal_context_capability sigh)
{
_handle_registry.sigh(node_handle, sigh);
}
void sync() { rump_sys_sync(); }
};
class File_system::Root : public Root_component<Session_component>
{
private:
Server::Entrypoint &_ep;
protected:
Session_component *_create_session(const char *args)
{
/*
* Determine client-specific policy defined implicitly by
* the client's label.
*/
char const *root_dir = ".";
bool writeable = false;
enum { ROOT_MAX_LEN = 256 };
char root[ROOT_MAX_LEN];
root[0] = 0;
try {
Session_label label(args);
Session_policy policy(label);
/*
* Determine directory that is used as root directory of
* the session.
*/
try {
policy.attribute("root").value(root, sizeof(root));
/*
* Make sure the root path is specified with a
* leading path delimiter. For performing the
* lookup, we skip the first character.
*/
if (root[0] != '/')
throw Lookup_failed();
root_dir = root;
} catch (Xml_node::Nonexistent_attribute) {
PERR("Missing \"root\" attribute in policy definition");
throw Root::Unavailable();
} catch (Lookup_failed) {
PERR("Session root directory \"%s\" does not exist", root);
throw Root::Unavailable();
}
/*
* Determine if write access is permitted for the session.
*/
try {
writeable = policy.attribute("writeable").has_value("yes");
} catch (Xml_node::Nonexistent_attribute) { }
} catch (Session_policy::No_policy_defined) {
PERR("Invalid session request, no matching policy");
throw Root::Unavailable();
}
size_t ram_quota =
Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
size_t tx_buf_size =
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
/*
* Check if donated ram quota suffices for session data,
* and communication buffer.
*/
size_t session_size = sizeof(Session_component) + tx_buf_size;
if (max((size_t)4096, session_size) > ram_quota) {
PERR("insufficient 'ram_quota', got %zd, need %zd",
ram_quota, session_size);
throw Root::Quota_exceeded();
}
return new (md_alloc())
Session_component(tx_buf_size, _ep, root_dir, writeable, *md_alloc());
}
public:
/**
* Constructor
*
* \param ep entrypoint
* \param sig_rec signal receiver used for handling the
* data-flow signals of packet streams
* \param md_alloc meta-data allocator
*/
Root(Server::Entrypoint &ep, Allocator &md_alloc)
:
Root_component<Session_component>(&ep.rpc_ep(), &md_alloc),
_ep(ep)
{ }
};
struct File_system::Main
{
Server::Entrypoint &ep;
/*
* Initialize root interface
*/
Sliced_heap sliced_heap = { env()->ram_session(), env()->rm_session() };
Root fs_root = { ep, sliced_heap };
Main(Server::Entrypoint &ep)
:
ep(ep)
{
File_system::init(ep);
env()->parent()->announce(ep.manage(fs_root));
}
};
/**********************
** Server framework **
**********************/
char const * Server::name() { return "rump_fs_ep"; }
Genode::size_t Server::stack_size() { return 2048 * sizeof(long); }
void Server::construct(Server::Entrypoint &ep) { static File_system::Main inst(ep); }

View File

@ -0,0 +1,121 @@
/*
* \brief File-system node
* \author Norman Feske
* \author Christian Helmuth
* \author Sebastian Sumpf
* \date 2013-11-11
*/
/*
* Copyright (C) 2013-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _NODE_H_
#define _NODE_H_
/* Genode includes */
#include <util/list.h>
#include <base/signal.h>
namespace File_system {
class Listener;
class Node;
}
class File_system::Listener : public List<Listener>::Element
{
private:
Signal_context_capability _sigh;
bool _marked_as_updated;
public:
Listener() : _marked_as_updated(false) { }
Listener(Signal_context_capability sigh)
: _sigh(sigh), _marked_as_updated(false) { }
void notify()
{
if (_marked_as_updated && _sigh.valid())
Signal_transmitter(_sigh).submit();
_marked_as_updated = false;
}
void mark_as_updated()
{
_marked_as_updated = true;
}
bool valid() const { return _sigh.valid(); }
};
class File_system::Node : public List<Node>::Element
{
public:
typedef char Name[128];
private:
Name _name;
unsigned long const _inode;
List<Listener> _listeners;
public:
Node(unsigned long inode) : _inode(inode) { _name[0] = 0; }
virtual ~Node()
{
/* propagate event to listeners */
mark_as_updated();
notify_listeners();
while (_listeners.first())
_listeners.remove(_listeners.first());
}
unsigned long inode() const { return _inode; }
char const *name() const { return _name; }
/**
* Assign name
*/
void name(char const *name) { strncpy(_name, name, sizeof(_name)); }
virtual size_t read(char *dst, size_t len, seek_off_t) = 0;
virtual size_t write(char const *src, size_t len, seek_off_t) = 0;
void add_listener(Listener *listener)
{
_listeners.insert(listener);
}
void remove_listener(Listener *listener)
{
_listeners.remove(listener);
}
void notify_listeners()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
curr->notify();
}
void mark_as_updated()
{
for (Listener *curr = _listeners.first(); curr; curr = curr->next())
curr->mark_as_updated();
}
};
#endif /* _NODE_H_ */

View File

@ -0,0 +1,184 @@
/*
* \brief Facility for managing the session-local node-handle namespace
* \author Norman Feske
* \date 2012-04-11
*/
/*
* Copyright (C) 2012-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _NODE_HANDLE_REGISTRY_H_
#define _NODE_HANDLE_REGISTRY_H_
namespace File_system {
class Node;
class Directory;
class File;
class Symlink;
/**
* Type trait for determining the node type for a given handle type
*/
template<typename T> struct Node_type;
template<> struct Node_type<Node_handle> { typedef Node Type; };
template<> struct Node_type<Dir_handle> { typedef Directory Type; };
template<> struct Node_type<File_handle> { typedef File Type; };
template<> struct Node_type<Symlink_handle> { typedef Symlink Type; };
/**
* Type trait for determining the handle type for a given node type
*/
template<typename T> struct Handle_type;
template<> struct Handle_type<Node> { typedef Node_handle Type; };
template<> struct Handle_type<Directory> { typedef Dir_handle Type; };
template<> struct Handle_type<File> { typedef File_handle Type; };
template<> struct Handle_type<Symlink> { typedef Symlink_handle Type; };
class Node_handle_registry
{
private:
/* maximum number of open nodes per session */
enum { MAX_NODE_HANDLES = 128U };
Node *_nodes[MAX_NODE_HANDLES];
/**
* Each open node handle can act as a listener to be informed about
* node changes.
*/
Listener _listeners[MAX_NODE_HANDLES];
/**
* Allocate node handle
*
* \throw Out_of_node_handles
*/
int _alloc(Node *node)
{
for (unsigned i = 0; i < MAX_NODE_HANDLES; i++)
if (!_nodes[i]) {
_nodes[i] = node;
return i;
}
throw Out_of_node_handles();
}
bool _in_range(int handle) const
{
return ((handle >= 0) && (handle < MAX_NODE_HANDLES));
}
public:
Node_handle_registry()
{
for (unsigned i = 0; i < MAX_NODE_HANDLES; i++)
_nodes[i] = 0;
}
template <typename NODE_TYPE>
typename Handle_type<NODE_TYPE>::Type alloc(NODE_TYPE *node)
{
typedef typename Handle_type<NODE_TYPE>::Type Handle;
return Handle(_alloc(node));
}
/**
* Release node handle
*/
void free(Node_handle handle)
{
if (!_in_range(handle.value))
return;
/*
* Notify listeners about the changed file.
*/
Node *node = dynamic_cast<Node *>(_nodes[handle.value]);
if (!node) { return; }
node->notify_listeners();
/*
* De-allocate handle
*/
Listener &listener = _listeners[handle.value];
if (listener.valid())
node->remove_listener(&listener);
_nodes[handle.value] = 0;
listener = Listener();
}
/**
* Lookup node using its handle as key
*
* \throw Invalid_handle
*/
template <typename HANDLE_TYPE>
typename Node_type<HANDLE_TYPE>::Type *lookup(HANDLE_TYPE handle)
{
if (!_in_range(handle.value))
throw Invalid_handle();
typedef typename Node_type<HANDLE_TYPE>::Type Node;
Node *node = dynamic_cast<Node *>(_nodes[handle.value]);
if (!node)
throw Invalid_handle();
return node;
}
bool refer_to_same_node(Node_handle h1, Node_handle h2) const
{
if (!_in_range(h1.value) || !_in_range(h2.value)) {
PDBG("refer_to_same_node -> Invalid_handle");
throw Invalid_handle();
}
return _nodes[h1.value] == _nodes[h2.value];
}
/**
* Register signal handler to be notified of node changes
*/
void sigh(Node_handle handle, Signal_context_capability sigh)
{
if (!_in_range(handle.value))
throw Invalid_handle();
Node *node = dynamic_cast<Node *>(_nodes[handle.value]);
if (!node) {
PDBG("Invalid_handle");
throw Invalid_handle();
}
Listener &listener = _listeners[handle.value];
/*
* If there was already a handler registered for the node,
* remove the old handler.
*/
if (listener.valid())
node->remove_listener(&listener);
/*
* Register new handler
*/
listener = Listener(sigh);
node->add_listener(&listener);
}
};
}
#endif /* _NODE_HANDLE_REGISTRY_H_ */

View File

@ -0,0 +1,71 @@
/**
* \brief Rump symlink node
* \author Sebastian Sumpf
* \date 2014-01-20
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SYMLINK_H_
#define _SYMLINK_H_
#include <os/path.h>
#include "node.h"
#include "util.h"
namespace File_system {
class Symlink;
}
class File_system::Symlink : public Node
{
private:
typedef Genode::Path<MAX_PATH_LEN> Path;
Path _path;
bool _create;
public:
Symlink(char const *dir, char const *name, bool create)
: Node(0), _path(name, dir), _create(create)
{
Node::name(name);
}
Symlink(char const *path)
: Node(0), _path(path), _create(false)
{
Node::name(basename(path));
}
size_t write(char const *src, size_t len, seek_off_t seek_offset)
{
if (!_create)
return 0;
int ret = rump_sys_symlink(src, _path.base());
return ret == -1 ? 0 : ret;
}
size_t read(char *dst, size_t len, seek_off_t seek_offset)
{
int ret = rump_sys_readlink(_path.base(), dst, len);
return ret == -1 ? 0 : ret;
}
file_size_t length()
{
char link_to[MAX_PATH_LEN];
return read(link_to, MAX_PATH_LEN, 0);
}
};
#endif /* _SYMLINK_H_ */

View File

@ -0,0 +1,5 @@
TARGET = rump_fs
SRC_CC = main.cc file_system.cc
LIBS = rump rump_fs server startup

View File

@ -0,0 +1,21 @@
/**
* \brief Undef macro clashes
* \author Sebastian Sumpf
* \date 2014-01-24
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _UNDEF_H_
#define _UNDEF_H_
extern "C" {
#include <sys/cdefs.h>
}
#endif /* _UNDEF_H_ */

View File

@ -0,0 +1,70 @@
/*
* \brief Utilities
* \author Norman Feske
* \date 2012-04-11
*/
/*
* Copyright (C) 2012-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _UTIL_H_
#define _UTIL_H_
/**
* Return base-name portion of null-terminated path string
*/
static inline char const *basename(char const *path)
{
char const *start = path;
for (; *path; path++)
if (*path == '/')
start = path + 1;
return start;
}
/**
* Return true if specified path is a base name (contains no path delimiters)
*/
static inline bool is_basename(char const *path)
{
for (; *path; path++)
if (*path == '/')
return false;
return true;
}
/**
* Return true if character 'c' occurs in null-terminated string 'str'
*/
static inline bool string_contains(char const *str, char c)
{
for (; *str; str++)
if (*str == c)
return true;
return false;
}
/**
* Return true if 'str' is a valid node name
*/
static inline bool valid_name(char const *str)
{
if (string_contains(str, '/')) return false;
/* must have at least one character */
if (str[0] == 0) return false;
return true;
}
#endif /* _UTIL_H_ */

View File

@ -12,10 +12,7 @@
*/
#include <base/printf.h>
#include <rom_session/connection.h>
#include <dataspace/client.h>
#include <rm_session/connection.h>
#include <base/thread.h>
#include <os/attached_rom_dataspace.h>
using namespace Genode;
@ -38,120 +35,31 @@ void dump(uint8_t *ptr, unsigned long offset)
}
class Pager : public Thread<8192>
{
private:
Signal_receiver _receiver;
Dataspace_capability _ds;
Rm_connection *_rm;
public:
Pager() : Thread("pager") { }
Signal_receiver *signal_receiver() { return &_receiver; }
void entry()
{
while (true) {
Signal signal = _receiver.wait_for_signal();
for (unsigned i = 0; i < signal.num(); i++)
handle_fault();
}
}
void handle_fault()
{
Rm_session::State state = _rm->state();
addr_t addr = state.addr & ~(0xfff);
_rm->attach_at(_ds, addr, 0x1000, addr - 0x1000);
}
void dataspace(Dataspace_capability ds) { _ds = ds; }
void rm(Rm_connection *rm) { _rm = rm; }
static Pager* pager()
{
static Pager _pager;
return &_pager;
}
static Pager* pager2()
{
static Pager _pager;
return &_pager;
}
static Pager* pager3()
{
static Pager _pager;
return &_pager;
}
};
int main()
{
Dataspace_capability ds;
Attached_rom_dataspace *ds;
uint8_t *ptr = 0;
static Signal_context context;
static Signal_context context2;
try {
Rom_connection rom("/test.txt");
rom.on_destruction(Rom_connection::KEEP_OPEN);
ds = rom.dataspace();
Dataspace_client client(ds);
ptr = env()->rm_session()->attach(ds);
printf("File size is %zx at %p\n", client.size(), ptr);
ds = new (env()->heap())Attached_rom_dataspace("/test.txt");
ptr = ds->local_addr<uint8_t>();
printf("File size is %zx at %p\n", ds->size(), ptr);
}
catch (...) {
PDBG("Rom error");
return 1;
}
Rm_connection rm(0, Dataspace_client(ds).size());
rm.fault_handler(Pager::pager()->signal_receiver()->manage(&context));
Pager::pager()->dataspace(ds);
Pager::pager()->rm(&rm);
/* start pager thread */
Pager::pager()->start();
uint8_t *ptr_nest = env()->rm_session()->attach(rm.dataspace());
Rm_connection rm2(0, Dataspace_client(ds).size());
rm2.fault_handler(Pager::pager2()->signal_receiver()->manage(&context2));
Pager::pager2()->dataspace(rm.dataspace());
Pager::pager2()->rm(&rm2);
Pager::pager2()->start();
uint8_t *ptr_nest2 = env()->rm_session()->attach(rm2.dataspace());
dump(ptr, 0x1000);
dump(ptr_nest, 0x2000);
dump(ptr_nest2, 0x3000);
dump(ptr, 0x10000);
dump(ptr, 0x20000);
dump(ptr, 0x1000);
dump(ptr_nest, 0x2000);
dump(ptr_nest2, 0x3000);
try {
Rom_connection rom("/notavail.txt");
PERR("found file where no file should be!");
}
catch (...) {
Attached_rom_dataspace rom("/notavail.txt");
if (!rom.is_valid())
PDBG("Expected ROM error occured");
return 1;
}
else
PERR("found file where no file should be!");
return 0;
}

View File

@ -38,3 +38,4 @@ gdb_monitor
part_blk
xml_generator
blk_cache
rump_ext2