diff --git a/repos/os/include/sandbox/sandbox.h b/repos/os/include/sandbox/sandbox.h index 9f2b7ce60f..54548611b5 100644 --- a/repos/os/include/sandbox/sandbox.h +++ b/repos/os/include/sandbox/sandbox.h @@ -44,6 +44,30 @@ class Genode::Sandbox : Noncopyable virtual void handle_sandbox_state() = 0; }; + /** + * Interface for accessing the PD intrinsics relevant to differentiate + * the regular use of core's PD service from a locally implemented PD + * service. + */ + struct Pd_intrinsics : Interface, Noncopyable + { + struct Intrinsics + { + Pd_session &ref_pd; + Capability ref_pd_cap; + Cpu_session &ref_cpu; + Capability ref_cpu_cap; + Region_map &address_space; + }; + + struct Fn : Interface { virtual void call(Intrinsics &) const = 0; }; + + /** + * Call 'Fn' with the 'Intrinsics' that apply for the specified PD + */ + virtual void with_intrinsics(Capability, Pd_session &, Fn const &) = 0; + }; + private: friend class Local_service_base; @@ -60,6 +84,15 @@ class Genode::Sandbox : Noncopyable Sandbox(Env &, State_handler &); + /** + * Constructor designated for monitoring PD-session operations + * + * The 'Pd_intrinsics' argument allows for the customization of the + * reference PD session used for quota transfers between the sandboxed + * children and the local runtime. + */ + Sandbox(Env &, State_handler &, Pd_intrinsics &); + void apply_config(Xml_node const &); /** @@ -196,6 +229,7 @@ struct Genode::Sandbox::Local_service : private Local_service_base Local_service(Sandbox &sandbox, Wakeup &wakeup) : Local_service_base(sandbox, ST::service_name(), wakeup) { } + using Local_session = ST; using Upgrade_response = Local_service_base::Upgrade_response; using Close_response = Local_service_base::Close_response; using Request = Local_service_base::Request; diff --git a/repos/os/lib/symbols/sandbox b/repos/os/lib/symbols/sandbox index 2e87285bb6..0025452386 100644 --- a/repos/os/lib/symbols/sandbox +++ b/repos/os/lib/symbols/sandbox @@ -6,4 +6,6 @@ _ZN6Genode7Sandbox18Local_service_baseC1ERS0_RKNS_6StringILm32EEERNS1_6WakeupE T _ZN6Genode7Sandbox18Local_service_baseC2ERS0_RKNS_6StringILm32EEERNS1_6WakeupE T _ZN6Genode7SandboxC1ERNS_3EnvERNS0_13State_handlerE T _ZN6Genode7SandboxC2ERNS_3EnvERNS0_13State_handlerE T +_ZN6Genode7SandboxC1ERNS_3EnvERNS0_13State_handlerERNS0_13Pd_intrinsicsE T +_ZN6Genode7SandboxC2ERNS_3EnvERNS0_13State_handlerERNS0_13Pd_intrinsicsE T _ZNK6Genode7Sandbox21generate_state_reportERNS_13Xml_generatorE T diff --git a/repos/os/src/lib/sandbox/child.cc b/repos/os/src/lib/sandbox/child.cc index b6d5cfb62c..9150e267fc 100644 --- a/repos/os/src/lib/sandbox/child.cc +++ b/repos/os/src/lib/sandbox/child.cc @@ -443,8 +443,6 @@ Sandbox::Child::Sample_state_result Sandbox::Child::sample_state() void Sandbox::Child::init(Pd_session &session, Pd_session_capability cap) { - session.ref_account(_env.pd_session_cap()); - size_t const initial_session_costs = session_alloc_batch_size()*_child.session_factory().session_costs(); @@ -472,13 +470,20 @@ void Sandbox::Child::init(Pd_session &session, Pd_session_capability cap) cap_quota = avail_caps; } - try { _env.pd().transfer_quota(cap, cap_quota); } - catch (Out_of_caps) { - error(name(), ": unable to initialize cap quota of PD"); } + _with_pd_intrinsics([&] (Pd_intrinsics::Intrinsics &intrinsics) { - try { _env.pd().transfer_quota(cap, ram_quota); } - catch (Out_of_ram) { - error(name(), ": unable to initialize RAM quota of PD"); } + _ref_pd_cap = intrinsics.ref_pd_cap; + + session.ref_account(intrinsics.ref_pd_cap); + + try { intrinsics.ref_pd.transfer_quota(cap, cap_quota); } + catch (Out_of_caps) { + error(name(), ": unable to initialize cap quota of PD"); } + + try { intrinsics.ref_pd.transfer_quota(cap, ram_quota); } + catch (Out_of_ram) { + error(name(), ": unable to initialize RAM quota of PD"); } + }); } @@ -491,9 +496,11 @@ void Sandbox::Child::init(Cpu_session &session, Cpu_session_capability cap) warning(name(), ": configured CPU quota of ", assigned, " exceeds " "available quota, proceeding with a quota of ", effective); - session.ref_account(_env.cpu_session_cap()); + _with_pd_intrinsics([&] (Pd_intrinsics::Intrinsics &intrinsics) { + session.ref_account(intrinsics.ref_cpu_cap); }); - _cpu_quota_transfer.transfer_cpu_quota(cap, effective); + _cpu_quota_transfer.transfer_cpu_quota(_child.pd_session_cap(), _child.pd(), + cap, effective); } @@ -745,7 +752,8 @@ Sandbox::Child::Child(Env &env, Affinity::Space const &affinity_space, Registry &parent_services, Registry &child_services, - Registry &local_services) + Registry &local_services, + Pd_intrinsics &pd_intrinsics) : _env(env), _alloc(alloc), _verbose(verbose), _id(id), _report_update_trigger(report_update_trigger), @@ -761,6 +769,7 @@ Sandbox::Child::Child(Env &env, _heartbeat_enabled(start_node.has_sub_node("heartbeat")), _resources(_resources_from_start_node(start_node, prio_levels, affinity_space, default_caps_accessor.default_caps())), + _pd_intrinsics(pd_intrinsics), _parent_services(parent_services), _child_services(child_services), _local_services(local_services), diff --git a/repos/os/src/lib/sandbox/child.h b/repos/os/src/lib/sandbox/child.h index 4634415809..674d7c8f8a 100644 --- a/repos/os/src/lib/sandbox/child.h +++ b/repos/os/src/lib/sandbox/child.h @@ -68,11 +68,35 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup struct Cpu_quota_transfer : Interface { - virtual void transfer_cpu_quota(Cpu_session_capability, Cpu_quota) = 0; + virtual void transfer_cpu_quota(Capability, Pd_session &, + Capability, Cpu_quota) = 0; }; enum class Sample_state_result { CHANGED, UNCHANGED }; + /* + * Helper for passing lambda functions as 'Pd_intrinsics::Fn' + */ + + using Pd_intrinsics = Genode::Sandbox::Pd_intrinsics; + + template + static void with_pd_intrinsics(Pd_intrinsics &pd_intrinsics, + Capability cap, PD_SESSION &pd, + FN const &fn) + { + struct Impl : Pd_intrinsics::Fn + { + using Intrinsics = Pd_intrinsics::Intrinsics; + + FN const &_fn; + Impl(FN const &fn) : _fn(fn) { } + void call(Intrinsics &intrinsics) const override { _fn(intrinsics); } + }; + + pd_intrinsics.with_intrinsics(cap, pd, Impl { fn }); + } + private: friend class Child_registry; @@ -280,6 +304,16 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup Ram_quota _configured_ram_quota() const; Cap_quota _configured_cap_quota() const; + Pd_intrinsics &_pd_intrinsics; + + template + void _with_pd_intrinsics(FN const &fn) + { + with_pd_intrinsics(_pd_intrinsics, _child.pd_session_cap(), _child.pd(), fn); + } + + Capability _ref_pd_cap { }; /* defined by 'init' */ + using Local_service = Genode::Sandbox::Local_service_base; Registry &_parent_services; @@ -293,7 +327,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup Child &_child; Dynamic_rom_session _session { _child._env.ep().rpc_ep(), - _child.ref_pd(), _child._env.rm(), + _child._env.ram(), _child._env.rm(), *this }; Service::Single_session_factory _factory { _session }; @@ -557,7 +591,8 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup Affinity::Space const &affinity_space, Registry &parent_services, Registry &child_services, - Registry &local_services); + Registry &local_services, + Pd_intrinsics &pd_intrinsics); virtual ~Child(); @@ -680,8 +715,17 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup Child_policy::Name name() const override { return _unique_name; } - Pd_session &ref_pd() override { return _env.pd(); } - Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); } + Pd_session &ref_pd() override + { + Pd_session *_ref_pd_ptr = nullptr; + _with_pd_intrinsics([&] (Pd_intrinsics::Intrinsics &intrinsics) { + _ref_pd_ptr = &intrinsics.ref_pd; }); + return *_ref_pd_ptr; + } + + Pd_session_capability ref_pd_cap() const override { return _ref_pd_cap; } + + Ram_allocator &session_md_ram() override { return _env.ram(); } void init(Pd_session &, Pd_session_capability) override; void init(Cpu_session &, Cpu_session_capability) override; @@ -732,6 +776,12 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup bool initiate_env_sessions() const override { return false; } + void _with_address_space(Pd_session &, With_address_space_fn const &fn) override + { + _with_pd_intrinsics([&] (Pd_intrinsics::Intrinsics &intrinsics) { + fn.call(intrinsics.address_space); }); + } + void yield_response() override { apply_downgrade(); diff --git a/repos/os/src/lib/sandbox/library.cc b/repos/os/src/lib/sandbox/library.cc index ddfef7ae9e..ab1e7f00d6 100644 --- a/repos/os/src/lib/sandbox/library.cc +++ b/repos/os/src/lib/sandbox/library.cc @@ -54,6 +54,8 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, Env &_env; Heap &_heap; + Pd_intrinsics &_pd_intrinsics; + Registry _parent_services { }; Registry _child_services { }; Registry &_local_services; @@ -143,7 +145,8 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, /** * Child::Cpu_quota_transfer interface */ - void transfer_cpu_quota(Cpu_session_capability cap, Cpu_quota quota) override + void transfer_cpu_quota(Capability pd_cap, Pd_session &pd, + Capability cpu, Cpu_quota quota) override { Cpu_quota const remaining { 100 - min(100u, _transferred_cpu.percent) }; @@ -154,7 +157,8 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, size_t const fraction = Cpu_session::quota_lim_upscale(quota.percent, remaining.percent); - _env.cpu().transfer_quota(cap, fraction); + Child::with_pd_intrinsics(_pd_intrinsics, pd_cap, pd, [&] (auto &intrinsics) { + intrinsics.ref_cpu.transfer_quota(cpu, fraction); }); _transferred_cpu.percent += quota.percent; } @@ -247,11 +251,38 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, return *new (_heap) Parent_service(_parent_services, _env, name); } + /** + * Default way of using the 'Env::pd' as the child's 'ref_pd' and accessing + * the child's address space via RPC. + */ + struct Default_pd_intrinsics : Pd_intrinsics + { + Env &_env; + + void with_intrinsics(Capability, Pd_session &pd, Fn const &fn) override + { + Region_map_client region_map(pd.address_space()); + + Intrinsics intrinsics { _env.pd(), _env.pd_session_cap(), + _env.cpu(), _env.cpu_session_cap(), region_map }; + fn.call(intrinsics); + } + + Default_pd_intrinsics(Env &env) : _env(env) { } + + } _default_pd_intrinsics { _env }; + + Library(Env &env, Heap &heap, Registry &local_services, + State_handler &state_handler, Pd_intrinsics &pd_intrinsics) + : + _env(env), _heap(heap), _pd_intrinsics(pd_intrinsics), + _local_services(local_services), _state_reporter(_env, *this, state_handler) + { } + Library(Env &env, Heap &heap, Registry &local_services, State_handler &state_handler) : - _env(env), _heap(heap), _local_services(local_services), - _state_reporter(_env, *this, state_handler) + Library(env, heap, local_services, state_handler, _default_pd_intrinsics) { } void apply_config(Xml_node const &); @@ -341,7 +372,8 @@ bool Genode::Sandbox::Library::ready_to_create_child(Start_model::Name const Child::Id { ++_child_cnt }, _state_reporter, start_node, *this, *this, _children, *this, *this, *this, *this, _prio_levels, _effective_affinity_space(), - _parent_services, _child_services, _local_services); + _parent_services, _child_services, _local_services, + _pd_intrinsics); _children.insert(&child); _avail_cpu.percent -= min(_avail_cpu.percent, child.cpu_quota().percent); @@ -627,6 +659,13 @@ void Genode::Sandbox::generate_state_report(Xml_generator &xml) const } +Genode::Sandbox::Sandbox(Env &env, State_handler &state_handler, Pd_intrinsics &pd_intrinsics) +: + _heap(env.ram(), env.rm()), + _library(*new (_heap) Library(env, _heap, _local_services, state_handler, pd_intrinsics)) +{ } + + Genode::Sandbox::Sandbox(Env &env, State_handler &state_handler) : _heap(env.ram(), env.rm()),