mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 12:32:56 +01:00
ealanos: Added new "Shell" service to control a habitat from a user-space component.
This commit is contained in:
27
repos/ealanos/include/ealanos/shell/client.h
Normal file
27
repos/ealanos/include/ealanos/shell/client.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef __EALANOS__INCLUDE__SHELL__CLIENT_H_
|
||||||
|
#define __EALANOS__INCLUDE__SHELL__CLIENT_H_
|
||||||
|
|
||||||
|
#include "base/capability.h"
|
||||||
|
#include "base/ram_allocator.h"
|
||||||
|
#include "region_map/region_map.h"
|
||||||
|
#include <base/rpc_client.h>
|
||||||
|
#include <ealanos/shell/session.h>
|
||||||
|
|
||||||
|
namespace Ealan
|
||||||
|
{
|
||||||
|
namespace Shell
|
||||||
|
{
|
||||||
|
using Capability = Genode::Capability<Ealan::Shell::Session>;
|
||||||
|
|
||||||
|
struct Client : Genode::Rpc_client<Ealan::Shell::Session> {
|
||||||
|
explicit Client(Capability cap) : Genode::Rpc_client<Ealan::Shell::Session>(cap) { }
|
||||||
|
|
||||||
|
Genode::Ram_dataspace_capability connect() override { return call<Rpc_connect>(); }
|
||||||
|
|
||||||
|
void disconnect() override { call<Rpc_disconnect>(); }
|
||||||
|
void commit() override { call<Rpc_commit>(); }
|
||||||
|
};
|
||||||
|
} // namespace Shell
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
43
repos/ealanos/include/ealanos/shell/component.h
Normal file
43
repos/ealanos/include/ealanos/shell/component.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#ifndef __EALANOS__INCLUDE__SHELL__COMPONENT_H_
|
||||||
|
#define __EALANOS__INCLUDE__SHELL__COMPONENT_H_
|
||||||
|
|
||||||
|
#include "base/capability.h"
|
||||||
|
#include "base/entrypoint.h"
|
||||||
|
#include "base/ram_allocator.h"
|
||||||
|
#include "region_map/region_map.h"
|
||||||
|
#include <base/rpc_server.h>
|
||||||
|
#include <base/session_label.h>
|
||||||
|
#include <root/component.h>
|
||||||
|
#include <base/session_object.h>
|
||||||
|
|
||||||
|
#include <ealanos/shell/session.h>
|
||||||
|
|
||||||
|
namespace Ealan {
|
||||||
|
class Hoitaja;
|
||||||
|
|
||||||
|
namespace Shell {
|
||||||
|
class Session_component : public Genode::Session_object<Ealan::Shell::Session>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genode::Entrypoint &_ep;
|
||||||
|
Ealan::Hoitaja &_hoitaja;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
template <typename... ARGS>
|
||||||
|
Session_component(Hoitaja &hoitaja, Genode::Entrypoint &ep,
|
||||||
|
Genode::Session::Resources const &res, ARGS &&...args)
|
||||||
|
: Genode::Session_object<Session>(ep, res, args...), _ep(ep), _hoitaja(hoitaja)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Genode::Ram_dataspace_capability connect() override;
|
||||||
|
void disconnect() override;
|
||||||
|
|
||||||
|
void commit() override;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} // namespace Ealan
|
||||||
|
|
||||||
|
#endif
|
||||||
33
repos/ealanos/include/ealanos/shell/connection.h
Normal file
33
repos/ealanos/include/ealanos/shell/connection.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef __EALANOS__INCLUDE__SHELL__CONNECTION_H_
|
||||||
|
#define __EALANOS__INCLUDE__SHELL__CONNECTION_H_
|
||||||
|
|
||||||
|
#include "base/affinity.h"
|
||||||
|
#include "base/capability.h"
|
||||||
|
#include "base/ram_allocator.h"
|
||||||
|
#include "region_map/region_map.h"
|
||||||
|
#include <base/connection.h>
|
||||||
|
#include <base/env.h>
|
||||||
|
|
||||||
|
#include <ealanos/shell/client.h>
|
||||||
|
|
||||||
|
namespace Ealan
|
||||||
|
{
|
||||||
|
namespace Shell
|
||||||
|
{
|
||||||
|
struct Connection : Genode::Connection<Session>, Client {
|
||||||
|
Connection(Genode::Env &env, Genode::Affinity affinity = Genode::Affinity(Genode::Affinity::Space(1,1), Genode::Affinity::Location(0,0)),
|
||||||
|
Label const &label = Label())
|
||||||
|
: Genode::Connection<Session>(env, label, Genode::Ram_quota{RAM_QUOTA},
|
||||||
|
affinity, Args("")), Client(cap())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Genode::Ram_dataspace_capability connect() override { return Client::connect(); }
|
||||||
|
|
||||||
|
void disconnect() override { Client::disconnect(); }
|
||||||
|
void commit() override { Client::commit(); }
|
||||||
|
|
||||||
|
};
|
||||||
|
} // namespace Shell
|
||||||
|
} // namespace Ealan
|
||||||
|
#endif
|
||||||
59
repos/ealanos/include/ealanos/shell/session.h
Normal file
59
repos/ealanos/include/ealanos/shell/session.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#ifndef __EALANOS__INCLUDE__SHELL__SESSION_H_
|
||||||
|
#define __EALANOS__INCLUDE__SHELL__SESSION_H_
|
||||||
|
|
||||||
|
#include "base/capability.h"
|
||||||
|
#include "base/ram_allocator.h"
|
||||||
|
#include "base/rpc.h"
|
||||||
|
#include "dataspace/capability.h"
|
||||||
|
#include "region_map/region_map.h"
|
||||||
|
#include <base/rpc_args.h>
|
||||||
|
#include <session/session.h>
|
||||||
|
#include <base/env.h>
|
||||||
|
|
||||||
|
namespace Ealan
|
||||||
|
{
|
||||||
|
namespace Shell
|
||||||
|
{
|
||||||
|
struct Session : Genode::Session
|
||||||
|
{
|
||||||
|
static const char *service_name() { return "Shell"; }
|
||||||
|
|
||||||
|
enum { CAP_QUOTA = 2, RAM_QUOTA = 1024 };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Connect to a shell session by supplying a region map
|
||||||
|
*
|
||||||
|
* @param rm - region map used for mapping the habitat's config to the client's virtual address space
|
||||||
|
* @return true - Mapping was successful
|
||||||
|
* @return false - An invalid region map was supplied or the mapping failed (e.g. lack of quota or caps)
|
||||||
|
*/
|
||||||
|
virtual Genode::Ram_dataspace_capability connect() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disconnects a client's shell session
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
virtual void disconnect() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Commit a change to the habitat's configuration made by the client.
|
||||||
|
* @details In order to let changes made in the habitat's configuration take effect, the
|
||||||
|
* changes must be reported by using this method. This will cause Hoitaja to
|
||||||
|
* re-read its configuration and applying any changes, such as creating new cells, destroying cells etc.
|
||||||
|
*/
|
||||||
|
virtual void commit() = 0;
|
||||||
|
|
||||||
|
/*****************
|
||||||
|
* RPC interface *
|
||||||
|
*****************/
|
||||||
|
|
||||||
|
GENODE_RPC(Rpc_connect, Genode::Ram_dataspace_capability, connect);
|
||||||
|
GENODE_RPC(Rpc_disconnect, void, disconnect);
|
||||||
|
GENODE_RPC(Rpc_commit, void, commit);
|
||||||
|
|
||||||
|
GENODE_RPC_INTERFACE(Rpc_connect, Rpc_disconnect, Rpc_commit);
|
||||||
|
};
|
||||||
|
} // namespace Shell
|
||||||
|
} // namespace Ealan
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -12,8 +12,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
|
#include "base/capability.h"
|
||||||
|
#include "base/ipc.h"
|
||||||
|
#include "base/ram_allocator.h"
|
||||||
|
#include "region_map/client.h"
|
||||||
|
#include "region_map/region_map.h"
|
||||||
#include <base/component.h>
|
#include <base/component.h>
|
||||||
#include <base/attached_rom_dataspace.h>
|
#include <base/attached_rom_dataspace.h>
|
||||||
|
#include <base/attached_ram_dataspace.h>
|
||||||
#include <sandbox/sandbox.h>
|
#include <sandbox/sandbox.h>
|
||||||
#include <os/reporter.h>
|
#include <os/reporter.h>
|
||||||
#include <base/log.h>
|
#include <base/log.h>
|
||||||
@@ -21,6 +27,10 @@
|
|||||||
#include <child.h>
|
#include <child.h>
|
||||||
|
|
||||||
#include <ealanos/laucher/component.h>
|
#include <ealanos/laucher/component.h>
|
||||||
|
|
||||||
|
#include <ealanos/shell/component.h>
|
||||||
|
|
||||||
|
#include <base/mutex.h>
|
||||||
namespace Ealan {
|
namespace Ealan {
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
@@ -31,7 +41,10 @@ namespace Ealan {
|
|||||||
|
|
||||||
class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_service_base::Wakeup
|
class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_service_base::Wakeup
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
friend class Ealan::Shell::Session_component;
|
||||||
|
|
||||||
Env &_env;
|
Env &_env;
|
||||||
|
|
||||||
Genode::Sandbox _sandbox { _env, *this };
|
Genode::Sandbox _sandbox { _env, *this };
|
||||||
@@ -40,6 +53,7 @@ class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_se
|
|||||||
|
|
||||||
Genode::Xml_node *_habitat_config{nullptr};
|
Genode::Xml_node *_habitat_config{nullptr};
|
||||||
|
|
||||||
|
Genode::Ram_dataspace_capability _config_ds{};
|
||||||
char *_config_dataspace{nullptr};
|
char *_config_dataspace{nullptr};
|
||||||
|
|
||||||
void _handle_resource_avail() { }
|
void _handle_resource_avail() { }
|
||||||
@@ -49,21 +63,23 @@ class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_se
|
|||||||
|
|
||||||
Constructible<Reporter> _reporter { };
|
Constructible<Reporter> _reporter { };
|
||||||
|
|
||||||
Genode::Rpc_entrypoint _ep{&_env.pd(), 4096, "launcher_ep", Genode::Affinity::Location(0, 0, 1, 1)};
|
|
||||||
|
|
||||||
Genode::Entrypoint _launcher_ep{_env, 4*4096, "launcher", Genode::Affinity::Location()};
|
|
||||||
|
|
||||||
Genode::Sliced_heap _md_alloc{_env.ram(), _env.rm()};
|
Genode::Sliced_heap _md_alloc{_env.ram(), _env.rm()};
|
||||||
|
|
||||||
Genode::Heap _heap{_env.ram(), _env.rm()};
|
Genode::Heap _heap{_env.ram(), _env.rm()};
|
||||||
|
|
||||||
|
Genode::Mutex _config_lock{};
|
||||||
|
|
||||||
using Launcher_service = Genode::Sandbox::Local_service<Ealan::Launcher_session_component>;
|
using Launcher_service = Genode::Sandbox::Local_service<Ealan::Launcher_session_component>;
|
||||||
Launcher_service _launcher_service{_sandbox, *this};
|
Launcher_service _launcher_service{_sandbox, *this};
|
||||||
|
|
||||||
|
using Shell_service = Genode::Sandbox::Local_service<Ealan::Shell::Session_component>;
|
||||||
|
Shell_service _shell_service{_sandbox, *this};
|
||||||
|
|
||||||
size_t _report_buffer_size = 0;
|
size_t _report_buffer_size = 0;
|
||||||
|
|
||||||
void _handle_config()
|
void _handle_config()
|
||||||
{
|
{
|
||||||
|
_config_lock.acquire();
|
||||||
_config.update();
|
_config.update();
|
||||||
|
|
||||||
if (_habitat_config) {
|
if (_habitat_config) {
|
||||||
@@ -71,7 +87,19 @@ class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_se
|
|||||||
delete _config_dataspace;
|
delete _config_dataspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
_config_dataspace = static_cast<char*>(_heap.alloc(_config.size()*32));
|
_config_ds = _env.ram().alloc(32 * _config.size());
|
||||||
|
|
||||||
|
Genode::Region_map::Attr attr{};
|
||||||
|
attr.writeable = true;
|
||||||
|
|
||||||
|
_config_dataspace = _env.rm()
|
||||||
|
.attach(_config_ds, attr)
|
||||||
|
.convert<char *>(
|
||||||
|
[&](Genode::Region_map::Range r) {
|
||||||
|
return reinterpret_cast<char*>(r.start);
|
||||||
|
},
|
||||||
|
[&](Genode::Region_map::Attach_error) { return nullptr; });
|
||||||
|
//_config_dataspace = static_cast<char*>(_heap.alloc(_config.size()*32));
|
||||||
Genode::memcpy(_config_dataspace, _config.local_addr<char*>(), _config.size());
|
Genode::memcpy(_config_dataspace, _config.local_addr<char*>(), _config.size());
|
||||||
_habitat_config = new (_sandbox._heap) Genode::Xml_node(_config_dataspace);
|
_habitat_config = new (_sandbox._heap) Genode::Xml_node(_config_dataspace);
|
||||||
|
|
||||||
@@ -96,6 +124,7 @@ class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_se
|
|||||||
_reporter->enabled(reporter_enabled);
|
_reporter->enabled(reporter_enabled);
|
||||||
|
|
||||||
_sandbox.apply_config(config);
|
_sandbox.apply_config(config);
|
||||||
|
_config_lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
Signal_handler<Hoitaja> _config_handler {
|
Signal_handler<Hoitaja> _config_handler {
|
||||||
@@ -136,31 +165,41 @@ class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_se
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
_config_lock.acquire();
|
||||||
Genode::log("Updating state of child ", child.name());
|
Genode::log("Updating state of child ", child.name());
|
||||||
_habitat_config = _sandbox.update(child, _habitat_config);
|
_habitat_config = _sandbox.update(child, _habitat_config);
|
||||||
Genode::log("Updated config length:", _habitat_config->content_size());
|
Genode::log("Updated config length:", _habitat_config->content_size());
|
||||||
|
_config_lock.release();
|
||||||
}
|
}
|
||||||
catch (Genode::Quota_guard<Genode::Cap_quota>::Limit_exceeded)
|
catch (Genode::Quota_guard<Genode::Cap_quota>::Limit_exceeded)
|
||||||
{
|
{
|
||||||
Genode::log("Caps exceeded while handling child state");
|
Genode::log("Caps exceeded while handling child state");
|
||||||
|
_config_lock.release();
|
||||||
_env.parent().exit(1);
|
_env.parent().exit(1);
|
||||||
}
|
}
|
||||||
catch (Genode::Ipc_error)
|
catch (Genode::Ipc_error)
|
||||||
{
|
{
|
||||||
Genode::error("Failed to update child state for <", child.name(), ">");
|
Genode::error("Failed to update child state for <", child.name(), ">");
|
||||||
|
_config_lock.release();
|
||||||
repeat = true;
|
repeat = true;
|
||||||
}
|
}
|
||||||
} while (repeat);
|
} while (repeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wakeup_local_service() override {
|
void wakeup_local_service() override {
|
||||||
_launcher_service.for_each_requested_session([&](Launcher_service::Request &req)
|
_launcher_service.for_each_requested_session([&](Launcher_service::Request &req) {
|
||||||
{ req.deliver_session(*new (_md_alloc) Ealan::Launcher_session_component(*this, _env.ep() , req.resources, "", req.diag)); });
|
req.deliver_session(*new (_md_alloc) Ealan::Launcher_session_component(
|
||||||
|
*this, _env.ep(), req.resources, "", req.diag));
|
||||||
|
});
|
||||||
|
_shell_service.for_each_requested_session([&](Shell_service::Request &req) {
|
||||||
|
req.deliver_session(*new (_md_alloc) Ealan::Shell::Session_component(*this, _env.ep(), req.resources, "", req.diag));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_cell_from_xml(const char *start_node){
|
void add_cell_from_xml(const char *start_node){
|
||||||
char *dest = nullptr;
|
char *dest = nullptr;
|
||||||
|
|
||||||
|
_config_lock.acquire();
|
||||||
_habitat_config->with_raw_content([&](char const *content, Genode::size_t)
|
_habitat_config->with_raw_content([&](char const *content, Genode::size_t)
|
||||||
{ dest = const_cast<char*>(content); });
|
{ dest = const_cast<char*>(content); });
|
||||||
dest += _habitat_config->content_size();
|
dest += _habitat_config->content_size();
|
||||||
@@ -183,8 +222,27 @@ class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_se
|
|||||||
repeat = true;
|
repeat = true;
|
||||||
}
|
}
|
||||||
} while (repeat);
|
} while (repeat);
|
||||||
|
_config_lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update_config()
|
||||||
|
{
|
||||||
|
_config_lock.acquire();
|
||||||
|
_sandbox._heap.free(_habitat_config, sizeof(Xml_node));
|
||||||
|
_habitat_config = new (_sandbox._heap) Xml_node(_config_dataspace);
|
||||||
|
|
||||||
|
bool repeat = false;
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
_sandbox.apply_config(*_habitat_config);
|
||||||
|
} catch (Genode::Ipc_error) {
|
||||||
|
Genode::warning("IPC error while applying new configuration.");
|
||||||
|
repeat = true;
|
||||||
|
}
|
||||||
|
} while (repeat);
|
||||||
|
_config_lock.release();
|
||||||
|
}
|
||||||
|
|
||||||
Hoitaja(Env &env) : _env(env)
|
Hoitaja(Env &env) : _env(env)
|
||||||
{
|
{
|
||||||
_config.sigh(_config_handler);
|
_config.sigh(_config_handler);
|
||||||
@@ -207,5 +265,26 @@ void Ealan::Launcher_session_component::launch(Genode::String<640> start_node)
|
|||||||
_hoitaja.add_cell_from_xml(start_node.string());
|
_hoitaja.add_cell_from_xml(start_node.string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************
|
||||||
|
* Shell server implementation *
|
||||||
|
*******************************/
|
||||||
|
|
||||||
|
Genode::Ram_dataspace_capability
|
||||||
|
Ealan::Shell::Session_component::connect()
|
||||||
|
{
|
||||||
|
return _hoitaja._config_ds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ealan::Shell::Session_component::disconnect()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ealan::Shell::Session_component::commit()
|
||||||
|
{
|
||||||
|
_hoitaja.update_config();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Component::construct(Genode::Env &env) { static Ealan::Hoitaja main(env); }
|
void Component::construct(Genode::Env &env) { static Ealan::Hoitaja main(env); }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user