mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 02:40:08 +00:00
sandbox: allow for customized PD access
By default, the sandbox uses the Env::pd() as reference PD session of the sandbox children. However, to accomodate use cases where the interplay of the reference PD session and the child's address space needs to be intercepted, this patch adds a constructor that takes an interface for the controlled access of PD intrinsics as argument. Issue #4917
This commit is contained in:
parent
30b70da6c1
commit
f2153f9b2f
@ -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<Pd_session> ref_pd_cap;
|
||||
Cpu_session &ref_cpu;
|
||||
Capability<Cpu_session> 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>, 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;
|
||||
|
@ -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
|
||||
|
@ -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); }
|
||||
_with_pd_intrinsics([&] (Pd_intrinsics::Intrinsics &intrinsics) {
|
||||
|
||||
_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 { _env.pd().transfer_quota(cap, ram_quota); }
|
||||
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_service> &parent_services,
|
||||
Registry<Routed_service> &child_services,
|
||||
Registry<Local_service> &local_services)
|
||||
Registry<Local_service> &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),
|
||||
|
@ -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>, Pd_session &,
|
||||
Capability<Cpu_session>, 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 <typename PD_SESSION, typename FN>
|
||||
static void with_pd_intrinsics(Pd_intrinsics &pd_intrinsics,
|
||||
Capability<Pd_session> 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 <typename FN>
|
||||
void _with_pd_intrinsics(FN const &fn)
|
||||
{
|
||||
with_pd_intrinsics(_pd_intrinsics, _child.pd_session_cap(), _child.pd(), fn);
|
||||
}
|
||||
|
||||
Capability<Pd_session> _ref_pd_cap { }; /* defined by 'init' */
|
||||
|
||||
using Local_service = Genode::Sandbox::Local_service_base;
|
||||
|
||||
Registry<Parent_service> &_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_service> &parent_services,
|
||||
Registry<Routed_service> &child_services,
|
||||
Registry<Local_service> &local_services);
|
||||
Registry<Local_service> &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();
|
||||
|
@ -54,6 +54,8 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer,
|
||||
Env &_env;
|
||||
Heap &_heap;
|
||||
|
||||
Pd_intrinsics &_pd_intrinsics;
|
||||
|
||||
Registry<Parent_service> _parent_services { };
|
||||
Registry<Routed_service> _child_services { };
|
||||
Registry<Local_service> &_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_session> pd_cap, Pd_session &pd,
|
||||
Capability<Cpu_session> 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_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_service> &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_service> &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()),
|
||||
|
Loading…
Reference in New Issue
Block a user