diff --git a/repos/os/recipes/src/shim/content.mk b/repos/os/recipes/src/shim/content.mk new file mode 100644 index 0000000000..d160016648 --- /dev/null +++ b/repos/os/recipes/src/shim/content.mk @@ -0,0 +1,2 @@ +SRC_DIR = src/app/shim +include $(GENODE_DIR)/repos/base/recipes/src/content.inc diff --git a/repos/os/recipes/src/shim/hash b/repos/os/recipes/src/shim/hash new file mode 100644 index 0000000000..7ff3a045eb --- /dev/null +++ b/repos/os/recipes/src/shim/hash @@ -0,0 +1 @@ +2021-03-03 540874a5d56d9f923516410d566337d6929e97ec diff --git a/repos/os/recipes/src/shim/used_apis b/repos/os/recipes/src/shim/used_apis new file mode 100644 index 0000000000..df967b96a5 --- /dev/null +++ b/repos/os/recipes/src/shim/used_apis @@ -0,0 +1 @@ +base diff --git a/repos/os/src/app/shim/main.cc b/repos/os/src/app/shim/main.cc new file mode 100644 index 0000000000..b2cb421b6d --- /dev/null +++ b/repos/os/src/app/shim/main.cc @@ -0,0 +1,131 @@ +/* + * \brief Shim component to de-couple a child from its parent + * \author Norman Feske + * \date 2021-02-25 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include + +namespace Shim { + + struct Main; + using namespace Genode; +} + + +class Shim::Main : public Child_policy +{ + private: + + using Parent_service = Registered; + using Parent_services = Registry; + + Env &_env; + + Heap _heap { _env.ram(), _env.rm() }; + + template + QUOTA _forwarded_quota(QUOTA total, QUOTA preserved) const + { + if (preserved.value > total.value) { + error("insufficient quota to spawn child " + "(have ", total, " need ", preserved, ")"); + throw typename Quota_guard::Limit_exceeded(); + } + + return QUOTA { total.value - preserved.value }; + } + + Cap_quota const _preserved_caps { Child::env_cap_quota().value + 10 }; + Ram_quota const _preserved_ram { Child::env_ram_quota().value + 256*1024 }; + + Cap_quota const _cap_quota = _forwarded_quota(_env.pd().avail_caps(), + _preserved_caps); + + Ram_quota const _ram_quota = _forwarded_quota(_env.pd().avail_ram(), + _preserved_ram); + + Parent_services _parent_services { }; + + Child _child { _env.rm(), _env.ep().rpc_ep(), *this }; + + Service &_matching_service(Service::Name const &name) + { + /* populate session-local parent service registry on demand */ + Service *service_ptr = nullptr; + _parent_services.for_each([&] (Parent_service &s) { + if (s.name() == name) + service_ptr = &s; }); + + if (service_ptr) + return *service_ptr; + + return *new (_heap) Parent_service(_parent_services, _env, name); + } + + /** + * Return sub string of label with leading child name stripped out + * + * \return character pointer to the scoped part of the label, + * or the original label if the label has no prefix + */ + char const *skip_name_prefix(char const *label, size_t const len) + { + if (len < 5) + return label; + + /* + * Skip label separator ' -> ' + */ + if (strcmp(" -> ", label, 4) != 0) + return label; + + return label + 4; + } + + public: + + Main(Env &env) : _env(env) { } + + + /**************************** + ** Child-policy interface ** + ****************************/ + + Name name() const override { return ""; } + + Binary_name binary_name() const override { return "binary"; } + + Pd_session &ref_pd() override { return _env.pd(); } + Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); } + + void init(Pd_session &pd, Pd_session_capability pd_cap) override + { + pd.ref_account(ref_pd_cap()); + ref_pd().transfer_quota(pd_cap, _cap_quota); + ref_pd().transfer_quota(pd_cap, _ram_quota); + } + + Route resolve_session_request(Service::Name const &name, + Session_label const &label, + Session::Diag const diag) override + { + return Route { .service = _matching_service(name), + .label = skip_name_prefix(label.string(), + label.length()), + .diag = diag }; + } +}; + + +void Component::construct(Genode::Env &env) { static Shim::Main main(env); } diff --git a/repos/os/src/app/shim/target.mk b/repos/os/src/app/shim/target.mk new file mode 100644 index 0000000000..4ec8f16572 --- /dev/null +++ b/repos/os/src/app/shim/target.mk @@ -0,0 +1,3 @@ +TARGET = shim +SRC_CC = main.cc +LIBS += base