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 */
|
||||
#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/attached_rom_dataspace.h>
|
||||
#include <base/attached_ram_dataspace.h>
|
||||
#include <sandbox/sandbox.h>
|
||||
#include <os/reporter.h>
|
||||
#include <base/log.h>
|
||||
@@ -21,6 +27,10 @@
|
||||
#include <child.h>
|
||||
|
||||
#include <ealanos/laucher/component.h>
|
||||
|
||||
#include <ealanos/shell/component.h>
|
||||
|
||||
#include <base/mutex.h>
|
||||
namespace Ealan {
|
||||
|
||||
using namespace Genode;
|
||||
@@ -32,6 +42,9 @@ namespace Ealan {
|
||||
class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_service_base::Wakeup
|
||||
{
|
||||
private:
|
||||
|
||||
friend class Ealan::Shell::Session_component;
|
||||
|
||||
Env &_env;
|
||||
|
||||
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::Ram_dataspace_capability _config_ds{};
|
||||
char *_config_dataspace{nullptr};
|
||||
|
||||
void _handle_resource_avail() { }
|
||||
@@ -49,21 +63,23 @@ class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_se
|
||||
|
||||
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::Heap _heap{_env.ram(), _env.rm()};
|
||||
|
||||
Genode::Mutex _config_lock{};
|
||||
|
||||
using Launcher_service = Genode::Sandbox::Local_service<Ealan::Launcher_session_component>;
|
||||
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;
|
||||
|
||||
void _handle_config()
|
||||
{
|
||||
_config_lock.acquire();
|
||||
_config.update();
|
||||
|
||||
if (_habitat_config) {
|
||||
@@ -71,7 +87,19 @@ class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_se
|
||||
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());
|
||||
_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);
|
||||
|
||||
_sandbox.apply_config(config);
|
||||
_config_lock.release();
|
||||
}
|
||||
|
||||
Signal_handler<Hoitaja> _config_handler {
|
||||
@@ -136,31 +165,41 @@ class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_se
|
||||
do
|
||||
{
|
||||
try {
|
||||
_config_lock.acquire();
|
||||
Genode::log("Updating state of child ", child.name());
|
||||
_habitat_config = _sandbox.update(child, _habitat_config);
|
||||
Genode::log("Updated config length:", _habitat_config->content_size());
|
||||
_config_lock.release();
|
||||
}
|
||||
catch (Genode::Quota_guard<Genode::Cap_quota>::Limit_exceeded)
|
||||
{
|
||||
Genode::log("Caps exceeded while handling child state");
|
||||
_config_lock.release();
|
||||
_env.parent().exit(1);
|
||||
}
|
||||
catch (Genode::Ipc_error)
|
||||
{
|
||||
Genode::error("Failed to update child state for <", child.name(), ">");
|
||||
_config_lock.release();
|
||||
repeat = true;
|
||||
}
|
||||
} while (repeat);
|
||||
}
|
||||
|
||||
void wakeup_local_service() override {
|
||||
_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)); });
|
||||
_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));
|
||||
});
|
||||
_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){
|
||||
char *dest = nullptr;
|
||||
|
||||
_config_lock.acquire();
|
||||
_habitat_config->with_raw_content([&](char const *content, Genode::size_t)
|
||||
{ dest = const_cast<char*>(content); });
|
||||
dest += _habitat_config->content_size();
|
||||
@@ -183,6 +222,25 @@ class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_se
|
||||
repeat = true;
|
||||
}
|
||||
} 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)
|
||||
@@ -207,5 +265,26 @@ void Ealan::Launcher_session_component::launch(Genode::String<640> start_node)
|
||||
_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); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user