From 9251b1ede8b16f70631c032a336b26cfa6e07537 Mon Sep 17 00:00:00 2001 From: Sebastian Sumpf Date: Thu, 5 Dec 2013 15:45:14 +0100 Subject: [PATCH] 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 --- .gitignore | 2 + dde_rump/Makefile | 64 +++ dde_rump/README | 57 ++ dde_rump/include/rump_fs/fs.h | 32 ++ dde_rump/include/util/allocator_fap.h | 219 ++++++++ dde_rump/include/util/hard_context.h | 65 +++ dde_rump/lib/import/import-rump.mk | 1 + dde_rump/lib/mk/arm/rump.mk | 4 + dde_rump/lib/mk/rump.inc | 23 + dde_rump/lib/mk/rump_base.inc | 92 ++++ dde_rump/lib/mk/rump_fs.mk | 23 + dde_rump/lib/mk/x86_32/rump.mk | 4 + dde_rump/lib/mk/x86_64/rump.mk | 4 + dde_rump/patches/build.patch | 57 ++ dde_rump/patches/evbarm.patch | 26 + dde_rump/patches/mk.patch | 13 + dde_rump/run/rump_ext2.run | 89 ++++ dde_rump/run/rump_fat.run | 89 ++++ dde_rump/run/rump_iso.run | 124 +++++ dde_rump/src/lib/rump/bootstrap.cc | 258 +++++++++ dde_rump/src/lib/rump/dl_interface.h | 70 +++ dde_rump/src/lib/rump/dummies.cc | 54 ++ dde_rump/src/lib/rump/hypercall.cc | 293 ++++++++++ dde_rump/src/lib/rump/io.cc | 342 ++++++++++++ dde_rump/src/lib/rump/sched.h | 43 ++ dde_rump/src/lib/rump/sync.cc | 503 ++++++++++++++++++ dde_rump/src/platform/rump.ld | 32 ++ dde_rump/src/server/rump_fs/directory.h | 254 +++++++++ dde_rump/src/server/rump_fs/file.h | 154 ++++++ dde_rump/src/server/rump_fs/file_system.cc | 171 ++++++ dde_rump/src/server/rump_fs/file_system.h | 38 ++ dde_rump/src/server/rump_fs/main.cc | 456 ++++++++++++++++ dde_rump/src/server/rump_fs/node.h | 121 +++++ .../src/server/rump_fs/node_handle_registry.h | 184 +++++++ dde_rump/src/server/rump_fs/symlink.h | 71 +++ dde_rump/src/server/rump_fs/target.mk | 5 + dde_rump/src/server/rump_fs/undef.h | 21 + dde_rump/src/server/rump_fs/util.h | 70 +++ os/src/test/iso/main.cc | 110 +--- tool/autopilot.list | 1 + 40 files changed, 4138 insertions(+), 101 deletions(-) create mode 100644 dde_rump/Makefile create mode 100644 dde_rump/README create mode 100644 dde_rump/include/rump_fs/fs.h create mode 100644 dde_rump/include/util/allocator_fap.h create mode 100644 dde_rump/include/util/hard_context.h create mode 100644 dde_rump/lib/import/import-rump.mk create mode 100644 dde_rump/lib/mk/arm/rump.mk create mode 100644 dde_rump/lib/mk/rump.inc create mode 100644 dde_rump/lib/mk/rump_base.inc create mode 100644 dde_rump/lib/mk/rump_fs.mk create mode 100644 dde_rump/lib/mk/x86_32/rump.mk create mode 100644 dde_rump/lib/mk/x86_64/rump.mk create mode 100644 dde_rump/patches/build.patch create mode 100644 dde_rump/patches/evbarm.patch create mode 100644 dde_rump/patches/mk.patch create mode 100644 dde_rump/run/rump_ext2.run create mode 100644 dde_rump/run/rump_fat.run create mode 100644 dde_rump/run/rump_iso.run create mode 100644 dde_rump/src/lib/rump/bootstrap.cc create mode 100644 dde_rump/src/lib/rump/dl_interface.h create mode 100644 dde_rump/src/lib/rump/dummies.cc create mode 100644 dde_rump/src/lib/rump/hypercall.cc create mode 100644 dde_rump/src/lib/rump/io.cc create mode 100644 dde_rump/src/lib/rump/sched.h create mode 100644 dde_rump/src/lib/rump/sync.cc create mode 100644 dde_rump/src/platform/rump.ld create mode 100644 dde_rump/src/server/rump_fs/directory.h create mode 100644 dde_rump/src/server/rump_fs/file.h create mode 100644 dde_rump/src/server/rump_fs/file_system.cc create mode 100644 dde_rump/src/server/rump_fs/file_system.h create mode 100644 dde_rump/src/server/rump_fs/main.cc create mode 100644 dde_rump/src/server/rump_fs/node.h create mode 100644 dde_rump/src/server/rump_fs/node_handle_registry.h create mode 100644 dde_rump/src/server/rump_fs/symlink.h create mode 100644 dde_rump/src/server/rump_fs/target.mk create mode 100644 dde_rump/src/server/rump_fs/undef.h create mode 100644 dde_rump/src/server/rump_fs/util.h diff --git a/.gitignore b/.gitignore index 05a22d571..1234a4573 100644 --- a/.gitignore +++ b/.gitignore @@ -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/ diff --git a/dde_rump/Makefile b/dde_rump/Makefile new file mode 100644 index 000000000..1e969fb8b --- /dev/null +++ b/dde_rump/Makefile @@ -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: diff --git a/dde_rump/README b/dde_rump/README new file mode 100644 index 000000000..fd62316ab --- /dev/null +++ b/dde_rump/README @@ -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: + +! +! +! +! +! + +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. + diff --git a/dde_rump/include/rump_fs/fs.h b/dde_rump/include/rump_fs/fs.h new file mode 100644 index 000000000..eb5dac47a --- /dev/null +++ b/dde_rump/include/rump_fs/fs.h @@ -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_ */ diff --git a/dde_rump/include/util/allocator_fap.h b/dde_rump/include/util/allocator_fap.h new file mode 100644 index 000000000..3d8e9a327 --- /dev/null +++ b/dde_rump/include/util/allocator_fap.h @@ -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 +#include +#include + + +namespace Allocator { + template class Backend_alloc; + template class Fap; +} + + +namespace Allocator { + + using namespace Genode; + + struct Default_allocator_policy + { + static int block() { return 0; } + static void unblock(int) { } + }; + + template + struct Policy_guard + { + int val; + Policy_guard() { val = POLICY::block(); } + ~Policy_guard() { POLICY::unblock(val); } + }; + + /** + * Back-end allocator for Genode's slab allocator + */ + template + 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 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 + class Fap + { + private: + + typedef Allocator::Backend_alloc 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_ */ diff --git a/dde_rump/include/util/hard_context.h b/dde_rump/include/util/hard_context.h new file mode 100644 index 000000000..374fcd6e3 --- /dev/null +++ b/dde_rump/include/util/hard_context.h @@ -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 +#include +#include +} + +#include + + +/************* + ** Threads ** + *************/ + +typedef void *(*func)(void *); + +namespace Timer { + class Connection; +}; + +class Hard_context : public Genode::Thread +{ + 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_ */ diff --git a/dde_rump/lib/import/import-rump.mk b/dde_rump/lib/import/import-rump.mk new file mode 100644 index 000000000..2e4f7ee6c --- /dev/null +++ b/dde_rump/lib/import/import-rump.mk @@ -0,0 +1 @@ +INC_DIR += $(LIBGCC_INC_DIR) $(BUILD_BASE_DIR)/var/libcache/rump/include diff --git a/dde_rump/lib/mk/arm/rump.mk b/dde_rump/lib/mk/arm/rump.mk new file mode 100644 index 000000000..3d7465cc3 --- /dev/null +++ b/dde_rump/lib/mk/arm/rump.mk @@ -0,0 +1,4 @@ + +RUMP_OPT = + +include $(REP_DIR)/lib/mk/rump_base.inc diff --git a/dde_rump/lib/mk/rump.inc b/dde_rump/lib/mk/rump.inc new file mode 100644 index 000000000..6ed8f6131 --- /dev/null +++ b/dde_rump/lib/mk/rump.inc @@ -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 : diff --git a/dde_rump/lib/mk/rump_base.inc b/dde_rump/lib/mk/rump_base.inc new file mode 100644 index 000000000..df6fa0e33 --- /dev/null +++ b/dde_rump/lib/mk/rump_base.inc @@ -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 : diff --git a/dde_rump/lib/mk/rump_fs.mk b/dde_rump/lib/mk/rump_fs.mk new file mode 100644 index 000000000..31a5f8c15 --- /dev/null +++ b/dde_rump/lib/mk/rump_fs.mk @@ -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)) + + diff --git a/dde_rump/lib/mk/x86_32/rump.mk b/dde_rump/lib/mk/x86_32/rump.mk new file mode 100644 index 000000000..20647d28c --- /dev/null +++ b/dde_rump/lib/mk/x86_32/rump.mk @@ -0,0 +1,4 @@ + +RUMP_OPT = -32 + +include $(REP_DIR)/lib/mk/rump_base.inc diff --git a/dde_rump/lib/mk/x86_64/rump.mk b/dde_rump/lib/mk/x86_64/rump.mk new file mode 100644 index 000000000..3d7465cc3 --- /dev/null +++ b/dde_rump/lib/mk/x86_64/rump.mk @@ -0,0 +1,4 @@ + +RUMP_OPT = + +include $(REP_DIR)/lib/mk/rump_base.inc diff --git a/dde_rump/patches/build.patch b/dde_rump/patches/build.patch new file mode 100644 index 000000000..6318bd644 --- /dev/null +++ b/dde_rump/patches/build.patch @@ -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") diff --git a/dde_rump/patches/evbarm.patch b/dde_rump/patches/evbarm.patch new file mode 100644 index 000000000..5c88284bd --- /dev/null +++ b/dde_rump/patches/evbarm.patch @@ -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] diff --git a/dde_rump/patches/mk.patch b/dde_rump/patches/mk.patch new file mode 100644 index 000000000..1d7de4c90 --- /dev/null +++ b/dde_rump/patches/mk.patch @@ -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} diff --git a/dde_rump/run/rump_ext2.run b/dde_rump/run/rump_ext2.run new file mode 100644 index 000000000..9a828906d --- /dev/null +++ b/dde_rump/run/rump_ext2.run @@ -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 { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +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" diff --git a/dde_rump/run/rump_fat.run b/dde_rump/run/rump_fat.run new file mode 100644 index 000000000..5be533bdf --- /dev/null +++ b/dde_rump/run/rump_fat.run @@ -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 { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +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" diff --git a/dde_rump/run/rump_iso.run b/dde_rump/run/rump_iso.run new file mode 100644 index 000000000..ced34fd44 --- /dev/null +++ b/dde_rump/run/rump_iso.run @@ -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 { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +# +# 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 " + +compare_output_to { +[init -> test-iso] File size is 31000 at +[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] +} + diff --git a/dde_rump/src/lib/rump/bootstrap.cc b/dde_rump/src/lib/rump/bootstrap.cc new file mode 100644 index 000000000..5c706fe6f --- /dev/null +++ b/dde_rump/src/lib/rump/bootstrap.cc @@ -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 +#include +#include +} + +#include +#include +#include + +#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(sym_base); + return &s[index]; + } + + Elf_Dyn const *elf_dyn(int index = 0) + { + Elf_Dyn const *d = static_cast(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; +} diff --git a/dde_rump/src/lib/rump/dl_interface.h b/dde_rump/src/lib/rump/dl_interface.h new file mode 100644 index 000000000..ccfa6235a --- /dev/null +++ b/dde_rump/src/lib/rump/dl_interface.h @@ -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 + +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_ */ diff --git a/dde_rump/src/lib/rump/dummies.cc b/dde_rump/src/lib/rump/dummies.cc new file mode 100644 index 000000000..953e13b4d --- /dev/null +++ b/dde_rump/src/lib/rump/dummies.cc @@ -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 + +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" */ diff --git a/dde_rump/src/lib/rump/hypercall.cc b/dde_rump/src/lib/rump/hypercall.cc new file mode 100644 index 000000000..004212817 --- /dev/null +++ b/dde_rump/src/lib/rump/hypercall.cc @@ -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 +#include +#include +#include +#include +#include + + +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(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; +} + diff --git a/dde_rump/src/lib/rump/io.cc b/dde_rump/src/lib/rump/io.cc new file mode 100644 index 000000000..27c59a6a5 --- /dev/null +++ b/dde_rump/src/lib/rump/io.cc @@ -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 +#include +#include +#include +#include +#include + + +static const bool verbose = false; + +enum { GENODE_FD = 64 }; + +struct Packet : Genode::List::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 _disp_ack; + Genode::Signal_dispatcher _disp_submit; + + + Genode::List *_pending() + { + static Genode::List _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 + (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(); +} + diff --git a/dde_rump/src/lib/rump/sched.h b/dde_rump/src/lib/rump/sched.h new file mode 100644 index 000000000..bdeb2db95 --- /dev/null +++ b/dde_rump/src/lib/rump/sched.h @@ -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 +#include +#include +#include +#include +} + +#include + +/* 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_ */ diff --git a/dde_rump/src/lib/rump/sync.cc b/dde_rump/src/lib/rump/sync.cc new file mode 100644 index 000000000..805af7e64 --- /dev/null +++ b/dde_rump/src/lib/rump/sync.cc @@ -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 +} +#include +#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); +} + diff --git a/dde_rump/src/platform/rump.ld b/dde_rump/src/platform/rump.ld new file mode 100644 index 000000000..d04c194fe --- /dev/null +++ b/dde_rump/src/platform/rump.ld @@ -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 +} diff --git a/dde_rump/src/server/rump_fs/directory.h b/dde_rump/src/server/rump_fs/directory.h new file mode 100644 index 000000000..c03d09532 --- /dev/null +++ b/dde_rump/src/server/rump_fs/directory.h @@ -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 + +/* 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 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_ */ diff --git a/dde_rump/src/server/rump_fs/file.h b/dde_rump/src/server/rump_fs/file.h new file mode 100644 index 000000000..38a4923c2 --- /dev/null +++ b/dde_rump/src/server/rump_fs/file.h @@ -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_ */ diff --git a/dde_rump/src/server/rump_fs/file_system.cc b/dde_rump/src/server/rump_fs/file_system.cc new file mode 100644 index 000000000..89e7f8233 --- /dev/null +++ b/dde_rump/src/server/rump_fs/file_system.cc @@ -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 +#include +#include +#include +#include +#include + +/** + * 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_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 \'\"/>)"); + _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); +} diff --git a/dde_rump/src/server/rump_fs/file_system.h b/dde_rump/src/server/rump_fs/file_system.h new file mode 100644 index 000000000..7484baa12 --- /dev/null +++ b/dde_rump/src/server/rump_fs/file_system.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +} + +#include +#include + +namespace File_system { + void init(Server::Entrypoint &ep); + bool supports_symlinks(); +} + +extern int errno; + +#endif /* _FILE_SYSTEM_H_ */ diff --git a/dde_rump/src/server/rump_fs/main.cc b/dde_rump/src/server/rump_fs/main.cc new file mode 100644 index 000000000..f83e1ea32 --- /dev/null +++ b/dde_rump/src/server/rump_fs/main.cc @@ -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 +#include +#include +#include +#include +#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 _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(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(node); + if (file) { + s.size = file->length(); + s.mode = File_system::Status::MODE_FILE; + return s; + } + + Directory *dir = dynamic_cast(node); + if (dir) { + s.size = dir->num_entries()*sizeof(Directory_entry); + s.mode = File_system::Status::MODE_DIRECTORY; + return s; + } + + Symlink *link = dynamic_cast(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 +{ + 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(&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); } + diff --git a/dde_rump/src/server/rump_fs/node.h b/dde_rump/src/server/rump_fs/node.h new file mode 100644 index 000000000..d2a8142ce --- /dev/null +++ b/dde_rump/src/server/rump_fs/node.h @@ -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 +#include + + +namespace File_system { + class Listener; + class Node; +} + +class File_system::Listener : public List::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::Element +{ + public: + + typedef char Name[128]; + + private: + + Name _name; + unsigned long const _inode; + + List _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_ */ diff --git a/dde_rump/src/server/rump_fs/node_handle_registry.h b/dde_rump/src/server/rump_fs/node_handle_registry.h new file mode 100644 index 000000000..527994997 --- /dev/null +++ b/dde_rump/src/server/rump_fs/node_handle_registry.h @@ -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 struct Node_type; + template<> struct Node_type { typedef Node Type; }; + template<> struct Node_type { typedef Directory Type; }; + template<> struct Node_type { typedef File Type; }; + template<> struct Node_type { typedef Symlink Type; }; + + + /** + * Type trait for determining the handle type for a given node type + */ + template struct Handle_type; + template<> struct Handle_type { typedef Node_handle Type; }; + template<> struct Handle_type { typedef Dir_handle Type; }; + template<> struct Handle_type { typedef File_handle Type; }; + template<> struct Handle_type { 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 Handle_type::Type alloc(NODE_TYPE *node) + { + typedef typename Handle_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(_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 Node_type::Type *lookup(HANDLE_TYPE handle) + { + if (!_in_range(handle.value)) + throw Invalid_handle(); + + typedef typename Node_type::Type Node; + Node *node = dynamic_cast(_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(_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_ */ diff --git a/dde_rump/src/server/rump_fs/symlink.h b/dde_rump/src/server/rump_fs/symlink.h new file mode 100644 index 000000000..b4dcf554d --- /dev/null +++ b/dde_rump/src/server/rump_fs/symlink.h @@ -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 + +#include "node.h" +#include "util.h" + +namespace File_system { + class Symlink; +} + +class File_system::Symlink : public Node +{ + private: + + typedef Genode::Path 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_ */ diff --git a/dde_rump/src/server/rump_fs/target.mk b/dde_rump/src/server/rump_fs/target.mk new file mode 100644 index 000000000..b251639a3 --- /dev/null +++ b/dde_rump/src/server/rump_fs/target.mk @@ -0,0 +1,5 @@ +TARGET = rump_fs +SRC_CC = main.cc file_system.cc +LIBS = rump rump_fs server startup + + diff --git a/dde_rump/src/server/rump_fs/undef.h b/dde_rump/src/server/rump_fs/undef.h new file mode 100644 index 000000000..05c33ab0b --- /dev/null +++ b/dde_rump/src/server/rump_fs/undef.h @@ -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 +} + +#endif /* _UNDEF_H_ */ diff --git a/dde_rump/src/server/rump_fs/util.h b/dde_rump/src/server/rump_fs/util.h new file mode 100644 index 000000000..23ad85a7f --- /dev/null +++ b/dde_rump/src/server/rump_fs/util.h @@ -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_ */ diff --git a/os/src/test/iso/main.cc b/os/src/test/iso/main.cc index e4db8af14..9084870ac 100644 --- a/os/src/test/iso/main.cc +++ b/os/src/test/iso/main.cc @@ -12,10 +12,7 @@ */ #include -#include -#include -#include -#include +#include 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(); + 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; } diff --git a/tool/autopilot.list b/tool/autopilot.list index c8e2af7c1..380d47ebf 100644 --- a/tool/autopilot.list +++ b/tool/autopilot.list @@ -38,3 +38,4 @@ gdb_monitor part_blk xml_generator blk_cache +rump_ext2