diff --git a/libports/lib/mk/libc_rom.mk b/libports/lib/mk/libc_rom.mk new file mode 100644 index 00000000000..ce167c4c94d --- /dev/null +++ b/libports/lib/mk/libc_rom.mk @@ -0,0 +1,6 @@ +SRC_CC = plugin.cc +LIBS += libc + +vpath plugin.cc $(REP_DIR)/src/lib/libc_rom + +SHARED_LIB = yes diff --git a/libports/src/lib/libc_rom/README b/libports/src/lib/libc_rom/README new file mode 100644 index 00000000000..60cc948b617 --- /dev/null +++ b/libports/src/lib/libc_rom/README @@ -0,0 +1,5 @@ +The 'libc_rom' plugin allows the use of Genode's ROM-session interface via file +operations of the C library. + +This implementation is very preliminary. It supports no file operations other +than open and read. diff --git a/libports/src/lib/libc_rom/plugin.cc b/libports/src/lib/libc_rom/plugin.cc new file mode 100644 index 00000000000..bd7d01560c0 --- /dev/null +++ b/libports/src/lib/libc_rom/plugin.cc @@ -0,0 +1,172 @@ +/* + * \brief Libc plugin that uses Genode's ROM session + * \author Norman Feske + * \date 2012-01-09 + */ + +/* + * Copyright (C) 2011-2012 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. + */ + +/* libc plugin interface */ +#include +#include + +/* libc includes */ +#include +#include +#include + +/* Genode includes */ +#include +#include +#include +#include + + +namespace { + + /** + * An open file descriptor for this plugin corresponds to a ROM connection + * + * The connection is created along with the context. + */ + struct Plugin_context : Libc::Plugin_context, Genode::Attached_rom_dataspace + { + Genode::off_t read_offset; + + Plugin_context(char const *filename) + : Genode::Attached_rom_dataspace(filename), read_offset(0) { } + }; + + + static inline Plugin_context *context(Libc::File_descriptor *fd) + { + return static_cast(fd->context); + } + + + class Plugin : public Libc::Plugin + { + private: + + bool _probe_rom(char const *filename) + { + try { + /* + * Create ROM connection as local variable. The connection + * gets closed automatically when leaving the scope of this + * function. + */ + Genode::Rom_connection rom(filename); + return true; + } catch (...) { + return false; + } + } + + public: + + /** + * Constructor + */ + Plugin() + { } + + bool supports_open(const char *path, int flags) + { + return _probe_rom(path); + } + + Libc::File_descriptor *open(const char *pathname, int flags) + { + Plugin_context *context = new (Genode::env()->heap()) + Plugin_context(pathname); + return Libc::file_descriptor_allocator()->alloc(this, context); + } + + int close(Libc::File_descriptor *fd) + { + Genode::destroy(Genode::env()->heap(), context(fd)); + Libc::file_descriptor_allocator()->free(fd); + return 0; + } + + ssize_t read(Libc::File_descriptor *fd, void *buf, ::size_t count) + { + Plugin_context *rom = context(fd); + + /* file read limit is the size of data space */ + Genode::size_t const max_size = rom->size(); + + /* shortcut to current read offset */ + Genode::off_t &read_offset = rom->read_offset; + + /* maximum read offset, clamped to dataspace size */ + Genode::off_t const end_offset = Genode::min(count + read_offset, max_size); + + /* source address within the dataspace */ + char const *src = rom->local_addr() + read_offset; + + /* check if end of file is reached */ + if (read_offset >= end_offset) + return 0; + + /* copy-out bytes from ROM dataspace */ + Genode::off_t num_bytes = end_offset - read_offset; + memcpy(buf, src, num_bytes); + + /* advance read offset */ + read_offset += num_bytes; + + return num_bytes; + } + + ::off_t lseek(Libc::File_descriptor *fd, ::off_t offset, int whence) + { + Plugin_context *rom = context(fd); + + switch (whence) { + + case SEEK_CUR: + + offset += rom->read_offset; + + /* + * falling through... + */ + + case SEEK_SET: + + if (offset > rom->size()) { + errno = EINVAL; + return (::off_t)(-1); + } + + rom->read_offset = offset; + break; + + case SEEK_END: + + rom->read_offset = rom->size(); + break; + + default: + errno = EINVAL; + return (::off_t)(-1); + } + + return rom->read_offset; + } + }; + +} /* unnamed namespace */ + + +void __attribute__((constructor)) init_libc_rom(void) +{ + static Plugin plugin; +}