From 07093407884cae73b2cd04a37ce28939db9662fd Mon Sep 17 00:00:00 2001 From: Johannes Schlatow Date: Fri, 18 Mar 2016 23:36:32 +0100 Subject: [PATCH] Component writing a ROM into a file-system session Fixes #1917 --- repos/os/run/rom_to_file.run | 84 ++++++++++++ repos/os/src/app/rom_to_file/README | 10 ++ repos/os/src/app/rom_to_file/main.cc | 170 +++++++++++++++++++++++++ repos/os/src/app/rom_to_file/target.mk | 3 + 4 files changed, 267 insertions(+) create mode 100644 repos/os/run/rom_to_file.run create mode 100644 repos/os/src/app/rom_to_file/README create mode 100644 repos/os/src/app/rom_to_file/main.cc create mode 100644 repos/os/src/app/rom_to_file/target.mk diff --git a/repos/os/run/rom_to_file.run b/repos/os/run/rom_to_file.run new file mode 100644 index 0000000000..06a497db34 --- /dev/null +++ b/repos/os/run/rom_to_file.run @@ -0,0 +1,84 @@ +assert_spec linux + +# +# Build +# + +build { core init drivers/timer + server/dynamic_rom + app/rom_to_file + server/lx_fs +} + +create_boot_directory + +# +# Generate config +# + +install_config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +# +# Boot image +# + +exec mkdir -p bin/fs_test + +build_boot_image { core init timer + dynamic_rom + rom_to_file + lx_fs + fs_test +} + +append qemu_args " -nographic " + +run_genode_until "finished" 10 + +set output [exec cat bin/fs_test/test] + +compare_output_to {} + +exec rm -r bin/fs_test diff --git a/repos/os/src/app/rom_to_file/README b/repos/os/src/app/rom_to_file/README new file mode 100644 index 0000000000..0907d24cd9 --- /dev/null +++ b/repos/os/src/app/rom_to_file/README @@ -0,0 +1,10 @@ +The rom_to_file component requests a ROM session and writes the content of the +ROM dataspace to a File_system. It responds to configuration and ROM-module +updates. + +The name of the ROM module must be specified via the 'rom' attribute of the +components '' node + +! + +See run/rom_to_file.run for an example. diff --git a/repos/os/src/app/rom_to_file/main.cc b/repos/os/src/app/rom_to_file/main.cc new file mode 100644 index 0000000000..13b993faeb --- /dev/null +++ b/repos/os/src/app/rom_to_file/main.cc @@ -0,0 +1,170 @@ +/* + * \brief Write content of ROM module to File_system + * \author Johannes Schlatow + * \date 2016-03-12 + */ + +/* + * Copyright (C) 2016 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. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +namespace Rom_to_file { + + using namespace Genode; + + struct Main; + + enum { + BLOCK_SIZE = 512, + QUEUE_SIZE = File_system::Session::TX_QUEUE_SIZE, + TX_BUF_SIZE = BLOCK_SIZE * (QUEUE_SIZE*2 + 1) + }; +} + + +struct Rom_to_file::Main +{ + Server::Entrypoint &_ep; + + Allocator_avl alloc; + + File_system::Connection _fs; + + Lazy_volatile_object _rom_ds; + + typedef Genode::String<100> Rom_name; + + /** + * Name of currently requested ROM module + * + * Solely used to detect configuration changes. + */ + Rom_name _rom_name; + + /** + * Signal handler that is invoked when the configuration or the ROM module + * changes. + */ + void _handle_update(unsigned); + + Signal_rpc_member
_update_dispatcher = + { _ep, *this, &Main::_handle_update }; + + Main(Server::Entrypoint &ep) : _ep(ep), alloc(env()->heap()), _fs(alloc, TX_BUF_SIZE) + { + config()->sigh(_update_dispatcher); + _handle_update(0); + } +}; + + +void Rom_to_file::Main::_handle_update(unsigned) +{ + config()->reload(); + + /* + * Query name of ROM module from config + */ + Rom_name rom_name; + try { + rom_name = config()->xml_node().attribute_value("rom", rom_name); + + } catch (...) { + PWRN("could not determine ROM name from config"); + return; + } + + /* + * If ROM name changed, reconstruct '_rom_ds' + */ + if (rom_name != _rom_name) { + _rom_ds.construct(rom_name.string()); + _rom_ds->sigh(_update_dispatcher); + _rom_name = rom_name; + } + + /* + * Update ROM module and print content to LOG + */ + if (_rom_ds.is_constructed()) { + _rom_ds->update(); + + if (_rom_ds->is_valid()) { + using namespace File_system; + + char dir_path[] = "/"; + const char *file_name = _rom_name.string(); + + try { + Dir_handle dir_handle = ensure_dir(_fs, dir_path); + Handle_guard dir_guard(_fs, dir_handle); + File_handle handle; + + handle = _fs.file(dir_handle, file_name, File_system::WRITE_ONLY, true); + + _fs.truncate(handle, 0); + + size_t len = max(strlen(_rom_ds->local_addr()), _rom_ds->size()); + size_t written = write(_fs, handle, _rom_ds->local_addr(), len, 0); + + if (written < len) { + PWRN("%zu of %zu bytes have been written", written, len); + } + + _fs.close(handle); + } catch (Permission_denied) { + PERR("%s%s: permission denied", dir_path, file_name); + + } catch (No_space) { + PERR("file system out of space"); + + } catch (Out_of_metadata) { + PERR("server ran out of memory"); + + } catch (Invalid_name) { + PERR("%s%s: invalid path", dir_path, file_name); + + } catch (Name_too_long) { + PERR("%s%s: name too long", dir_path, file_name); + + } catch (...) { + PERR("cannot open file %s%s", dir_path, file_name); + throw; + } + } else { + PLOG("ROM '%s' is invalid", _rom_name.string()); + } + } +} + + +namespace Server { + + char const *name() { return "rom_to_file_ep"; } + + size_t stack_size() { return 4*1024*sizeof(long); } + + void construct(Entrypoint &ep) + { + static Rom_to_file::Main main(ep); + } +} diff --git a/repos/os/src/app/rom_to_file/target.mk b/repos/os/src/app/rom_to_file/target.mk new file mode 100644 index 0000000000..f574d896bb --- /dev/null +++ b/repos/os/src/app/rom_to_file/target.mk @@ -0,0 +1,3 @@ +TARGET = rom_to_file +SRC_CC = main.cc +LIBS = base config server