From c0a7565c219969d32707f63c0d2e52924f33b189 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Thu, 25 Feb 2021 13:32:22 +0100 Subject: [PATCH] os: shim helper for safe routing of env sessions This shim component can be used in case where env sessions of child (i.e., child's PD session) must be routed to another child of init. Without the shim, init would directly need to interact with these sessions and would thereby make itself dependent of the server's behavior. RPC calls to a server hosted as a child lead to all kinds of problems such as livelock situations, and putting the robustness of init at the whim of its child. With the shim, init merely needs to bootstrap the shim component by routing the shim's env sessions to core as usual. The server is only used for the sessions for the actual application hosted atop the shim. Issue #3837 Issue #4029 --- repos/os/recipes/src/shim/content.mk | 2 + repos/os/recipes/src/shim/hash | 1 + repos/os/recipes/src/shim/used_apis | 1 + repos/os/src/app/shim/main.cc | 131 +++++++++++++++++++++++++++ repos/os/src/app/shim/target.mk | 3 + 5 files changed, 138 insertions(+) create mode 100644 repos/os/recipes/src/shim/content.mk create mode 100644 repos/os/recipes/src/shim/hash create mode 100644 repos/os/recipes/src/shim/used_apis create mode 100644 repos/os/src/app/shim/main.cc create mode 100644 repos/os/src/app/shim/target.mk 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