genode/repos/ports/src/noux/main.cc

312 lines
8.4 KiB
C++
Raw Normal View History

2011-12-22 16:19:25 +01:00
/*
* \brief Unix emulation environment for Genode
* \author Norman Feske
* \date 2011-02-14
*/
/*
* Copyright (C) 2011-2017 Genode Labs GmbH
2011-12-22 16:19:25 +01:00
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
2011-12-22 16:19:25 +01:00
*/
/* Genode includes */
#include <timer_session/connection.h>
#include <base/component.h>
#include <libc/component.h>
2011-12-22 16:19:25 +01:00
/* Noux includes */
#include <child.h>
#include <construct.h>
#include <noux_session/sysio.h>
2011-12-22 16:19:25 +01:00
#include <vfs_io_channel.h>
#include <terminal_io_channel.h>
#include <user_info.h>
#include <io_receptor_registry.h>
#include <destruct_queue.h>
#include <kill_broadcaster.h>
#include <vfs/dir_file_system.h>
2011-12-22 16:19:25 +01:00
namespace Noux {
static Noux::Child *init_child;
static int exit_value = ~0;
2011-12-22 16:19:25 +01:00
bool init_process(Child *child) { return child == init_child; }
void init_process_exited(int exit) { init_child = 0; exit_value = exit; }
2011-12-22 16:19:25 +01:00
}
extern void init_network();
2011-12-22 16:19:25 +01:00
Noux::Io_receptor_registry * Noux::io_receptor_registry()
2011-12-22 16:19:25 +01:00
{
static Noux::Io_receptor_registry _inst;
return &_inst;
2011-12-22 16:19:25 +01:00
}
/**
* Return string containing the environment variables of init
*
* The variable definitions are separated by zeros. The end of the string is
* marked with another zero.
2011-12-22 16:19:25 +01:00
*/
2016-11-25 16:54:49 +01:00
static Noux::Sysio::Env &env_string_of_init_process(Genode::Xml_node config)
2011-12-22 16:19:25 +01:00
{
static Noux::Sysio::Env env;
int index = 0;
2011-12-22 16:19:25 +01:00
/* read environment variables for init process from config */
2016-11-25 16:54:49 +01:00
Genode::Xml_node start_node = config.sub_node("start");
2011-12-22 16:19:25 +01:00
try {
Genode::Xml_node arg_node = start_node.sub_node("env");
for (; ; arg_node = arg_node.next("env")) {
static char name_buf[256], value_buf[256];
arg_node.attribute("name").value(name_buf, sizeof(name_buf));
arg_node.attribute("value").value(value_buf, sizeof(value_buf));
Genode::size_t env_var_size = Genode::strlen(name_buf) +
Genode::strlen("=") +
Genode::strlen(value_buf) + 1;
if (index + env_var_size < sizeof(env)) {
Genode::snprintf(&env[index], env_var_size, "%s=%s", name_buf, value_buf);
index += env_var_size;
} else {
env[index] = 0;
break;
}
2011-12-22 16:19:25 +01:00
}
}
catch (Genode::Xml_node::Nonexistent_sub_node) { }
return env;
2011-12-22 16:19:25 +01:00
}
namespace Noux { class Stdio_unavailable : Genode::Exception { }; }
2016-11-25 16:54:49 +01:00
/*
* \throw Stdio_unavailable
*/
static Noux::Io_channel &
connect_stdio(Genode::Env &env,
Genode::Constructible<Terminal::Connection> &terminal,
Genode::Xml_node config,
Vfs::Dir_file_system &root,
Noux::Terminal_io_channel::Type type,
Genode::Allocator &alloc)
{
using namespace Vfs;
using namespace Noux;
typedef Terminal_io_channel Tio; /* just a local abbreviation */
2016-11-25 16:54:49 +01:00
typedef Genode::String<MAX_PATH_LEN> Path;
Vfs_handle *vfs_handle = nullptr;
char const *stdio_name = "";
unsigned mode = 0;
switch (type) {
case Tio::STDIN:
stdio_name = "stdin";
mode = Directory_service::OPEN_MODE_RDONLY;
break;
case Tio::STDOUT:
stdio_name = "stdout";
mode = Directory_service::OPEN_MODE_WRONLY;
break;
case Tio::STDERR:
stdio_name = "stderr";
mode = Directory_service::OPEN_MODE_WRONLY;
break;
};
2016-11-25 16:54:49 +01:00
if (!config.has_attribute(stdio_name)) {
if (!terminal.constructed())
terminal.construct(env);
2016-11-25 16:54:49 +01:00
warning(stdio_name, " VFS path not defined, connecting to terminal session");
return *new (alloc) Tio(*terminal, type, env.ep());
2016-11-25 16:54:49 +01:00
}
2016-11-25 16:54:49 +01:00
Path const path = config.attribute_value(stdio_name, Path());
2016-11-25 16:54:49 +01:00
if (root.open(path.string(), mode, &vfs_handle, alloc)
!= Directory_service::OPEN_OK)
{
error("failed to connect ", stdio_name, " to '", path, "'");
throw Stdio_unavailable();
}
2016-11-25 16:54:49 +01:00
return *new (alloc)
Vfs_io_channel(path.string(), root.leaf_path(path.string()), &root,
vfs_handle, env.ep());
}
/*
* This lock is needed to delay the insertion of signals into a child object.
* This is necessary during an 'execve()' syscall, when signals get copied from
* the old child object to the new one. Without the lock, an IO channel could
* insert a signal into both objects, which could lead to a duplicated signal
* in the new child object.
*/
Genode::Lock &Noux::signal_lock()
{
static Genode::Lock inst;
return inst;
}
namespace Noux { struct Main; }
struct Noux::Main
{
Env &_env;
Heap _heap { _env.ram(), _env.rm() };
/* whitelist of service requests to be routed to the parent */
Noux::Parent_services _parent_services;
Noux::Parent_service _log_parent_service { _parent_services, "LOG" };
Noux::Parent_service _timer_parent_service { _parent_services, "Timer" };
Attached_rom_dataspace _config { _env, "config" };
2011-12-22 16:19:25 +01:00
Verbose _verbose { _config.xml() };
2011-12-22 16:19:25 +01:00
/**
* Return name of init process as specified in the config
*/
Child_policy::Name _name_of_init_process() const
{
return _config.xml().sub_node("start").attribute_value("name", Child_policy::Name());
}
/**
* Read command-line arguments of init process from config
*/
Args const &_args_of_init_process()
{
static char args_buf[4096];
static Args args(args_buf, sizeof(args_buf));
Xml_node start_node = _config.xml().sub_node("start");
try {
/* the first argument is the program name */
args.append(_name_of_init_process().string());
2011-12-22 16:19:25 +01:00
start_node.for_each_sub_node("arg", [&] (Xml_node arg_node) {
typedef String<512> Value;
args.append(arg_node.attribute_value("value", Value()).string());
});
2011-12-22 16:19:25 +01:00
} catch (Args::Overrun) { error("argument buffer overrun"); }
2016-11-25 16:54:49 +01:00
return args;
}
2016-11-25 16:54:49 +01:00
/* initialize virtual file system */
Vfs::Global_file_system_factory _global_file_system_factory { _heap };
struct Io_response_handler : Vfs::Io_response_handler
{
void handle_io_response(Vfs::Vfs_handle::Context *) override { }
} _io_response_handler;
Vfs::Dir_file_system _root_dir { _env, _heap, _config.xml().sub_node("fstab"),
_io_response_handler,
_global_file_system_factory };
Pid_allocator _pid_allocator;
Timeout_scheduler _timeout_scheduler { _env };
User_info _user_info { _config.xml() };
2011-12-22 16:19:25 +01:00
bool _network_initialized = (init_network(), true);
Signal_handler<Main> _destruct_handler {
_env.ep(), *this, &Main::_handle_destruct };
Destruct_queue _destruct_queue { _destruct_handler };
void _handle_destruct()
{
_destruct_queue.flush();
2011-12-22 16:19:25 +01:00
/* let noux exit if the init process exited */
if (!init_child)
_env.parent().exit(exit_value);
}
struct Kill_broadcaster_impl: Kill_broadcaster
{
Family_member *init_process = nullptr;
bool kill(int pid, Noux::Sysio::Signal sig)
{
return init_process->deliver_kill(pid, sig);
}
} _kill_broadcaster;
Noux::Child _init_child { _name_of_init_process(),
_verbose,
_user_info,
0,
_kill_broadcaster,
_timeout_scheduler,
_init_child,
_pid_allocator,
_pid_allocator.alloc(),
_env,
_root_dir,
_args_of_init_process(),
env_string_of_init_process(_config.xml()),
_heap,
Capability quota accounting and trading This patch mirrors the accounting and trading scheme that Genode employs for physical memory to the accounting of capability allocations. Capability quotas must now be explicitly assigned to subsystems by specifying a 'caps=<amount>' attribute to init's start nodes. Analogously to RAM quotas, cap quotas can be traded between clients and servers as part of the session protocol. The capability budget of each component is maintained by the component's corresponding PD session at core. At the current stage, the accounting is applied to RPC capabilities, signal-context capabilities, and dataspace capabilities. Capabilities that are dynamically allocated via core's CPU and TRACE service are not yet covered. Also, the capabilities allocated by resource multiplexers outside of core (like nitpicker) must be accounted by the respective servers, which is not covered yet. If a component runs out of capabilities, core's PD service prints a warning to the log. To observe the consumption of capabilities per component in detail, the PD service is equipped with a diagnostic mode, which can be enabled via the 'diag' attribute in the target node of init's routing rules. E.g., the following route enables the diagnostic mode for the PD session of the "timer" component: <default-route> <service name="PD" unscoped_label="timer"> <parent diag="yes"/> </service> ... </default-route> For subsystems based on a sub-init instance, init can be configured to report the capability-quota information of its subsystems by adding the attribute 'child_caps="yes"' to init's '<report>' config node. Init's own capability quota can be reported by adding the attribute 'init_caps="yes"'. Fixes #2398
2017-05-08 21:35:43 +02:00
_env.pd(),
_env.pd_session_cap(),
_parent_services,
false,
_destruct_queue };
Constructible<Terminal::Connection> _terminal;
2011-12-22 16:19:25 +01:00
/*
* I/O channels must be dynamically allocated to handle cases where the
* init program closes one of these.
*/
typedef Terminal_io_channel Tio; /* just a local abbreviation */
Shared_pointer<Io_channel>
_channel_0 { &connect_stdio(_env, _terminal, _config.xml(), _root_dir, Tio::STDIN, _heap), _heap },
_channel_1 { &connect_stdio(_env, _terminal, _config.xml(), _root_dir, Tio::STDOUT, _heap), _heap },
_channel_2 { &connect_stdio(_env, _terminal, _config.xml(), _root_dir, Tio::STDERR, _heap), _heap };
2011-12-22 16:19:25 +01:00
Main(Env &env) : _env(env)
{
log("--- noux started ---");
2011-12-22 16:19:25 +01:00
_init_child.add_io_channel(_channel_0, 0);
_init_child.add_io_channel(_channel_1, 1);
_init_child.add_io_channel(_channel_2, 2);
2011-12-22 16:19:25 +01:00
_kill_broadcaster.init_process = &_init_child;
init_child = &_init_child;
_init_child.start();
2011-12-22 16:19:25 +01:00
}
};
2011-12-22 16:19:25 +01:00
void noux_construct(Genode::Env &env)
{
static Noux::Main main(env);
}