From 1bf7967463237268a1e1e56d34c8ce3b9339edd8 Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Tue, 12 Jun 2012 14:23:45 +0200 Subject: [PATCH] Noux terminal file system This patch adds a new "terminal" file system type to Noux, which allows to create a "character device" file that is connected to a Genode 'Terminal' service. The 'Terminal' session created by the file system has the label "noux(terminal_fs)" to distinguish it from the 'Terminal' session created by Noux itself. Fixes #244. --- ports/include/noux_session/sysio.h | 1 + ports/run/noux_terminal_fs.run | 219 ++++++++++++++++++++++++++ ports/src/lib/libc_noux/plugin.cc | 1 + ports/src/noux/dir_file_system.h | 6 + ports/src/noux/terminal_file_system.h | 210 ++++++++++++++++++++++++ 5 files changed, 437 insertions(+) create mode 100644 ports/run/noux_terminal_fs.run create mode 100644 ports/src/noux/terminal_file_system.h diff --git a/ports/include/noux_session/sysio.h b/ports/include/noux_session/sysio.h index d95de1c21a..12fb5bb91a 100644 --- a/ports/include/noux_session/sysio.h +++ b/ports/include/noux_session/sysio.h @@ -120,6 +120,7 @@ namespace Noux { DIRENT_TYPE_FILE, DIRENT_TYPE_DIRECTORY, DIRENT_TYPE_FIFO, + DIRENT_TYPE_CHARDEV, DIRENT_TYPE_SYMLINK, DIRENT_TYPE_END }; diff --git a/ports/run/noux_terminal_fs.run b/ports/run/noux_terminal_fs.run new file mode 100644 index 0000000000..c25136549c --- /dev/null +++ b/ports/run/noux_terminal_fs.run @@ -0,0 +1,219 @@ +# +# \brief Test for the Noux terminal file system +# \author Christian Prochaska +# \date 2012-06-11 +# + +# +# The test shows two framebuffer terminals. The upper terminal runs an +# interatctive shell and the lower terminal can be accessed from the shell via +# /dev/terminal. +# +# Example for writing to the lower terminal: echo "test" > /dev/terminal +# Example for reading a line from the lower terminal: head -n 1 /dev/terminal +# + +set build_components { + core init drivers/timer noux lib/libc_noux + drivers/framebuffer drivers/pci drivers/input + server/terminal server/ram_fs server/nitpicker + server/nit_fb +} + +# +# Build Noux packages only once +# +foreach pkg {bash coreutils} { + lappend_if [expr ![file exists bin/$pkg]] build_components noux-pkg/$pkg } + +build $build_components + +# strip all binaries prior archiving +exec sh -c "find bin/bash/ bin/coreutils/ -type f | (xargs strip || true) 2>/dev/null" + +exec tar cfv bin/bash.tar -h -C bin/bash . +exec tar cfv bin/coreutils.tar -h -C bin/coreutils . + +create_boot_directory + +append config { + + + + + + + + + + + + + + + + + + + + + } + +append_if [have_spec sdl] config { + + + + + + + } + +append_if [have_spec pci] config { + + + + } + +append_if [have_spec vesa] config { + + + + } + +append_if [have_spec pl11x] config { + + + + } + +append_if [have_spec ps2] config { + + + + } + +append config { + + + + } +append_if [have_spec ps2] config { + } +append_if [have_spec vesa] config { + } +append_if [have_spec pl11x] config { + } +append config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +install_config $config + + +# +# Boot modules +# + +# generic modules +set boot_modules { + core init timer ld.lib.so noux terminal ram_fs nitpicker nit_fb + libc.lib.so libm.lib.so libc_noux.lib.so + bash.tar coreutils.tar +} + +# platform-specific modules +lappend_if [have_spec linux] boot_modules fb_sdl +lappend_if [have_spec pci] boot_modules pci_drv +lappend_if [have_spec vesa] boot_modules vesa_drv +lappend_if [have_spec ps2] boot_modules ps2_drv +lappend_if [have_spec pl11x] boot_modules pl11x_drv + +build_boot_image $boot_modules + +if {[have_spec x86_64]} { + # bash.tar is really huge when built for x86_64 + append qemu_args " -m 300 " +} + +run_genode_until forever + +exec rm bin/bash.tar diff --git a/ports/src/lib/libc_noux/plugin.cc b/ports/src/lib/libc_noux/plugin.cc index ac564b1e33..2d12de69c1 100644 --- a/ports/src/lib/libc_noux/plugin.cc +++ b/ports/src/lib/libc_noux/plugin.cc @@ -931,6 +931,7 @@ namespace { case Noux::Sysio::DIRENT_TYPE_FILE: dirent->d_type = DT_REG; break; case Noux::Sysio::DIRENT_TYPE_SYMLINK: dirent->d_type = DT_LNK; break; case Noux::Sysio::DIRENT_TYPE_FIFO: dirent->d_type = DT_FIFO; break; + case Noux::Sysio::DIRENT_TYPE_CHARDEV: dirent->d_type = DT_CHR; break; case Noux::Sysio::DIRENT_TYPE_END: return 0; } diff --git a/ports/src/noux/dir_file_system.h b/ports/src/noux/dir_file_system.h index e548dbb5f8..5572f9973f 100644 --- a/ports/src/noux/dir_file_system.h +++ b/ports/src/noux/dir_file_system.h @@ -22,6 +22,7 @@ #include #include #include +#include namespace Noux { @@ -90,6 +91,11 @@ namespace Noux { continue; } + if (sub_node.has_type("terminal")) { + _append_file_system(new Terminal_file_system(sub_node)); + continue; + } + { char type_name[64]; sub_node.type_name(type_name, sizeof(type_name)); diff --git a/ports/src/noux/terminal_file_system.h b/ports/src/noux/terminal_file_system.h new file mode 100644 index 0000000000..de0669750c --- /dev/null +++ b/ports/src/noux/terminal_file_system.h @@ -0,0 +1,210 @@ +/* + * \brief Terminal file system + * \author Christian Prochaska + * \date 2012-05-23 + */ + +/* + * Copyright (C) 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. + */ + +#ifndef _NOUX__TERMINAL_FILE_SYSTEM_H_ +#define _NOUX__TERMINAL_FILE_SYSTEM_H_ + +/* Genode includes */ +#include +#include +#include +#include + +/* Noux includes */ +#include +#include "file_system.h" + + +namespace Noux { + + class Terminal_file_system : public File_system + { + private: + + Terminal::Session_client _terminal; + Signal_context _read_avail_sig_ctx; + Signal_receiver _read_avail_sig_rec; + + enum { FILENAME_MAX_LEN = 64 }; + char _filename[FILENAME_MAX_LEN]; + + bool _is_root(const char *path) + { + return (strcmp(path, "") == 0) || (strcmp(path, "/") == 0); + } + + bool _is_terminal_file(const char *path) + { + return (strlen(path) == (strlen(_filename) + 1)) && + (strcmp(&path[1], _filename) == 0); + } + + public: + + Terminal_file_system(Xml_node config) + : _terminal(env()->parent()->session + ("ram_quota=8192, label=\"noux(terminal_fs)\"")) + { + _filename[0] = 0; + try { config.attribute("name").value(_filename, sizeof(_filename)); } + catch (...) { } + + /* + * Wait for connection-established signal + */ + + /* create signal receiver, just for the single signal */ + Signal_context sig_ctx; + Signal_receiver sig_rec; + Signal_context_capability sig_cap = sig_rec.manage(&sig_ctx); + + /* register signal handler */ + _terminal.connected_sigh(sig_cap); + + /* wati for signal */ + sig_rec.wait_for_signal(); + sig_rec.dissolve(&sig_ctx); + + /* + * Register "read available" signal handler + */ + _terminal.read_avail_sigh(_read_avail_sig_rec.manage(&_read_avail_sig_ctx)); + } + + + /********************************* + ** Directory-service interface ** + *********************************/ + + Dataspace_capability dataspace(char const *path) + { + /* not supported */ + return Dataspace_capability(); + } + + void release(char const *path, Dataspace_capability ds_cap) + { + /* not supported */ + } + + bool stat(Sysio *sysio, char const *path) + { + Sysio::Stat st = { 0, 0, 0, 0, 0, 0 }; + + if (_is_root(path)) + st.mode = Sysio::STAT_MODE_DIRECTORY; + else if (_is_terminal_file(path)) { + st.mode = Sysio::STAT_MODE_CHARDEV; + } else { + sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY; + return false; + } + + sysio->stat_out.st = st; + return true; + } + + bool dirent(Sysio *sysio, char const *path, off_t index) + { + if (_is_root(path)) { + if (index == 0) { + sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_CHARDEV; + strncpy(sysio->dirent_out.entry.name, + _filename, + sizeof(sysio->dirent_out.entry.name)); + } else { + sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_END; + } + + return true; + } + + return false; + } + + size_t num_dirent(char const *path) + { + if (_is_root(path)) + return 1; + else + return 0; + } + + bool is_directory(char const *path) + { + if (_is_root(path)) + return true; + + return false; + } + + char const *leaf_path(char const *path) + { + return path; + } + + Vfs_handle *open(Sysio *sysio, char const *path) + { + if (!_is_terminal_file(path)) { + sysio->error.open = Sysio::OPEN_ERR_UNACCESSIBLE; + return 0; + } + + return new (env()->heap()) Vfs_handle(this, this, 0); + } + + bool unlink(Sysio *sysio, char const *path) + { + /* not supported */ + return false; + } + + bool rename(Sysio *sysio, char const *from_path, char const *to_path) + { + /* not supported */ + return false; + } + + bool mkdir(Sysio *sysio, char const *path) + { + /* not supported */ + return false; + } + + /*************************** + ** File_system interface ** + ***************************/ + + char const *name() const { return "terminal"; } + + + /******************************** + ** File I/O service interface ** + ********************************/ + + bool write(Sysio *sysio, Vfs_handle *handle) + { + sysio->write_out.count = _terminal.write(sysio->write_in.chunk, sysio->write_in.count); + return true; + } + + bool read(Sysio *sysio, Vfs_handle *vfs_handle) + { + _read_avail_sig_rec.wait_for_signal(); + sysio->read_out.count = _terminal.read(sysio->read_out.chunk, sysio->read_in.count); + return true; + } + }; +} + +#endif /* _NOUX__TERMINAL_FILE_SYSTEM_H_ */