mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 21:27:56 +00:00
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:
parent
ce27985b8a
commit
9251b1ede8
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
64
dde_rump/Makefile
Normal 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
57
dde_rump/README
Normal 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.
|
||||
|
32
dde_rump/include/rump_fs/fs.h
Normal file
32
dde_rump/include/rump_fs/fs.h
Normal 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_ */
|
219
dde_rump/include/util/allocator_fap.h
Normal file
219
dde_rump/include/util/allocator_fap.h
Normal 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_ */
|
65
dde_rump/include/util/hard_context.h
Normal file
65
dde_rump/include/util/hard_context.h
Normal 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_ */
|
1
dde_rump/lib/import/import-rump.mk
Normal file
1
dde_rump/lib/import/import-rump.mk
Normal file
@ -0,0 +1 @@
|
||||
INC_DIR += $(LIBGCC_INC_DIR) $(BUILD_BASE_DIR)/var/libcache/rump/include
|
4
dde_rump/lib/mk/arm/rump.mk
Normal file
4
dde_rump/lib/mk/arm/rump.mk
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
RUMP_OPT =
|
||||
|
||||
include $(REP_DIR)/lib/mk/rump_base.inc
|
23
dde_rump/lib/mk/rump.inc
Normal file
23
dde_rump/lib/mk/rump.inc
Normal 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 :
|
92
dde_rump/lib/mk/rump_base.inc
Normal file
92
dde_rump/lib/mk/rump_base.inc
Normal 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 :
|
23
dde_rump/lib/mk/rump_fs.mk
Normal file
23
dde_rump/lib/mk/rump_fs.mk
Normal 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))
|
||||
|
||||
|
4
dde_rump/lib/mk/x86_32/rump.mk
Normal file
4
dde_rump/lib/mk/x86_32/rump.mk
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
RUMP_OPT = -32
|
||||
|
||||
include $(REP_DIR)/lib/mk/rump_base.inc
|
4
dde_rump/lib/mk/x86_64/rump.mk
Normal file
4
dde_rump/lib/mk/x86_64/rump.mk
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
RUMP_OPT =
|
||||
|
||||
include $(REP_DIR)/lib/mk/rump_base.inc
|
57
dde_rump/patches/build.patch
Normal file
57
dde_rump/patches/build.patch
Normal 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")
|
26
dde_rump/patches/evbarm.patch
Normal file
26
dde_rump/patches/evbarm.patch
Normal 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
13
dde_rump/patches/mk.patch
Normal 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}
|
89
dde_rump/run/rump_ext2.run
Normal file
89
dde_rump/run/rump_ext2.run
Normal 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
89
dde_rump/run/rump_fat.run
Normal 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
124
dde_rump/run/rump_iso.run
Normal 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]
|
||||
}
|
||||
|
258
dde_rump/src/lib/rump/bootstrap.cc
Normal file
258
dde_rump/src/lib/rump/bootstrap.cc
Normal 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;
|
||||
}
|
70
dde_rump/src/lib/rump/dl_interface.h
Normal file
70
dde_rump/src/lib/rump/dl_interface.h
Normal 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_ */
|
54
dde_rump/src/lib/rump/dummies.cc
Normal file
54
dde_rump/src/lib/rump/dummies.cc
Normal 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" */
|
293
dde_rump/src/lib/rump/hypercall.cc
Normal file
293
dde_rump/src/lib/rump/hypercall.cc
Normal 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
342
dde_rump/src/lib/rump/io.cc
Normal 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();
|
||||
}
|
||||
|
43
dde_rump/src/lib/rump/sched.h
Normal file
43
dde_rump/src/lib/rump/sched.h
Normal 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_ */
|
503
dde_rump/src/lib/rump/sync.cc
Normal file
503
dde_rump/src/lib/rump/sync.cc
Normal 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);
|
||||
}
|
||||
|
32
dde_rump/src/platform/rump.ld
Normal file
32
dde_rump/src/platform/rump.ld
Normal 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
|
||||
}
|
254
dde_rump/src/server/rump_fs/directory.h
Normal file
254
dde_rump/src/server/rump_fs/directory.h
Normal 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_ */
|
154
dde_rump/src/server/rump_fs/file.h
Normal file
154
dde_rump/src/server/rump_fs/file.h
Normal 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_ */
|
171
dde_rump/src/server/rump_fs/file_system.cc
Normal file
171
dde_rump/src/server/rump_fs/file_system.cc
Normal 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);
|
||||
}
|
38
dde_rump/src/server/rump_fs/file_system.h
Normal file
38
dde_rump/src/server/rump_fs/file_system.h
Normal 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_ */
|
456
dde_rump/src/server/rump_fs/main.cc
Normal file
456
dde_rump/src/server/rump_fs/main.cc
Normal 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); }
|
||||
|
121
dde_rump/src/server/rump_fs/node.h
Normal file
121
dde_rump/src/server/rump_fs/node.h
Normal 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_ */
|
184
dde_rump/src/server/rump_fs/node_handle_registry.h
Normal file
184
dde_rump/src/server/rump_fs/node_handle_registry.h
Normal 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_ */
|
71
dde_rump/src/server/rump_fs/symlink.h
Normal file
71
dde_rump/src/server/rump_fs/symlink.h
Normal 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_ */
|
5
dde_rump/src/server/rump_fs/target.mk
Normal file
5
dde_rump/src/server/rump_fs/target.mk
Normal file
@ -0,0 +1,5 @@
|
||||
TARGET = rump_fs
|
||||
SRC_CC = main.cc file_system.cc
|
||||
LIBS = rump rump_fs server startup
|
||||
|
||||
|
21
dde_rump/src/server/rump_fs/undef.h
Normal file
21
dde_rump/src/server/rump_fs/undef.h
Normal 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_ */
|
70
dde_rump/src/server/rump_fs/util.h
Normal file
70
dde_rump/src/server/rump_fs/util.h
Normal 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_ */
|
@ -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;
|
||||
}
|
||||
|
@ -38,3 +38,4 @@ gdb_monitor
|
||||
part_blk
|
||||
xml_generator
|
||||
blk_cache
|
||||
rump_ext2
|
||||
|
Loading…
Reference in New Issue
Block a user