/* * \brief Application child * \author Christian Prochaska * \date 2009-10-05 */ /* * Copyright (C) 2009-2017 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. */ #ifndef _APP_CHILD_H_ #define _APP_CHILD_H_ /* Genode includes */ #include #include #include #include #include /* sandbox library private includes */ #include /* GDB monitor includes */ #include "genode_child_resources.h" #include "cpu_session_component.h" #include "pd_session_component.h" #include "rom.h" #include "child_config.h" namespace Gdb_monitor { using namespace Genode; class App_child; } class Gdb_monitor::App_child : public Child_policy, public Async_service::Wakeup, public Sandbox::Report_update_trigger, public Sandbox::Routed_service::Pd_accessor, public Sandbox::Routed_service::Ram_accessor { private: typedef Registered Parent_service; typedef Registry Parent_services; typedef Registry Child_services; /** * gdbserver blocks in 'select()', so a separate entrypoint is used. */ struct Local_env : Genode::Env { Genode::Env &genode_env; Genode::Entrypoint local_ep { genode_env, 4*1024*sizeof(addr_t), "target_ep", Affinity::Location() }; Local_env(Env &genode_env) : genode_env(genode_env) { } Parent &parent() override { return genode_env.parent(); } Cpu_session &cpu() override { return genode_env.cpu(); } Region_map &rm() override { return genode_env.rm(); } Pd_session &pd() override { return genode_env.pd(); } Entrypoint &ep() override { return local_ep; } Cpu_session_capability cpu_session_cap() override { return genode_env.cpu_session_cap(); } Pd_session_capability pd_session_cap() override { return genode_env.pd_session_cap(); } Id_space &id_space() override { return genode_env.id_space(); } Pd_session_capability ram_session_cap() { return pd_session_cap(); } Pd_session &ram() { return pd(); } Session_capability session(Parent::Service_name const &service_name, Parent::Client::Id id, Parent::Session_args const &session_args, Affinity const &affinity) override { return genode_env.session(service_name, id, session_args, affinity); } void upgrade(Parent::Client::Id id, Parent::Upgrade_args const &args) override { return genode_env.upgrade(id, args); } void close(Parent::Client::Id id) override { return genode_env.close(id); } void exec_static_constructors() override { } void reinit(Native_capability::Raw raw) override { genode_env.reinit(raw); } void reinit_main_thread(Capability &stack_area_rm) override { genode_env.reinit_main_thread(stack_area_rm); } }; Local_env _env; Allocator &_alloc; Pd_session_capability _ref_pd_cap { _env.pd_session_cap() }; Pd_session &_ref_pd { _env.pd() }; const char *_unique_name; Dataspace_capability _elf_ds; Region_map &_rm; Ram_quota _ram_quota; Cap_quota _cap_quota; Parent_services _parent_services; Child_services _child_services; Init::Child_config _child_config; Init::Child_policy_provide_rom_file _config_policy; Genode_child_resources _genode_child_resources; Signal_handler _unresolved_page_fault_handler; Dataspace_pool _managed_ds_map; Pd_session_component _pd { _env.ep().rpc_ep(), _env, _alloc, _unique_name, _managed_ds_map }; Pd_service::Single_session_factory _pd_factory { _pd }; Pd_service _pd_service { _pd_factory }; Local_cpu_factory _cpu_factory; Cpu_service _cpu_service { _cpu_factory }; Local_rom_factory _rom_factory; Rom_service _rom_service { _rom_factory }; Genode::Session_requester _session_requester { _env.ep().rpc_ep(), _env.ram(), _env.rm() }; Sandbox::Server _server { _env, _alloc, _child_services, *this }; Child *_child; void _handle_unresolved_page_fault() { _genode_child_resources.cpu_session_component().handle_unresolved_page_fault(); } template static Service *_find_service(Registry &services, Service::Name const &name) { Service *service = nullptr; services.for_each([&] (T &s) { if (!service && (s.name() == name)) service = &s; }); return service; } /** * Child_service::Wakeup callback */ void wakeup_async_service() override { _session_requester.trigger_update(); } /** * Sandbox::Report_update_trigger callbacks */ void trigger_report_update() override { } void trigger_immediate_report_update() override { } /** * Sandbox::Routed_service::Pd_accessor interface */ Pd_session &pd() override { return _child->pd(); } Pd_session_capability pd_cap() const override { return _child->pd_session_cap(); } /** * Sandbox::Routed_service::Ram_accessor interface */ Pd_session &ram() override { return _child->pd(); } Pd_session_capability ram_cap() const override { return _child->pd_session_cap(); } Service &_matching_service(Service::Name const &service_name, Session_label const &label) { Service *service = nullptr; /* check for config file request */ if ((service = _config_policy.resolve_session_request_with_label(service_name, label))) return *service; /* check for "session_requests" ROM request */ if ((service_name == Genode::Rom_session::service_name()) && (label.last_element() == Genode::Session_requester::rom_name())) return _session_requester.service(); if (service_name == "CPU") return _cpu_service; if (service_name == "PD") return _pd_service; if (service_name == "ROM") return _rom_service; service = _find_service(_parent_services, service_name); if (!service) service = new (_alloc) Parent_service(_parent_services, _env, service_name); if (!service) throw Service_denied(); return *service; } public: /** * Constructor */ App_child(Env &env, Allocator &alloc, char const *unique_name, Ram_quota ram_quota, Cap_quota cap_quota, Entrypoint &signal_ep, Xml_node target_node, int const new_thread_pipe_write_end, int const breakpoint_len, unsigned char const *breakpoint_data) : _env(env), _alloc(alloc), _unique_name(unique_name), _rm(_env.rm()), _ram_quota(ram_quota), _cap_quota(cap_quota), _child_config(_env.ram(), _rm, target_node), _config_policy("config", _child_config.dataspace(), &_env.ep().rpc_ep()), _unresolved_page_fault_handler(signal_ep, *this, &App_child::_handle_unresolved_page_fault), _cpu_factory(_env, _env.ep().rpc_ep(), _alloc, _pd.core_pd_cap(), signal_ep, new_thread_pipe_write_end, breakpoint_len, breakpoint_data, &_genode_child_resources), _rom_factory(_env, _env.ep().rpc_ep(), _alloc) { _genode_child_resources.region_map_component(&_pd.region_map()); _pd.region_map().fault_handler(_unresolved_page_fault_handler); } ~App_child() { _child_services.for_each([&] (Sandbox::Routed_service &service) { destroy(_alloc, &service); }); destroy(_alloc, _child); } Genode_child_resources *genode_child_resources() { return &_genode_child_resources; } void start() { _child = new (_alloc) Child(_rm, _env.ep().rpc_ep(), *this); } /**************************** ** Child-policy interface ** ****************************/ Name name() const override { return _unique_name; } Pd_session &ref_pd() override { return _ref_pd; } Pd_session_capability ref_pd_cap() const override { return _ref_pd_cap; } Id_space &server_id_space() override { return _session_requester.id_space(); } void init(Pd_session &session, Pd_session_capability cap) override { session.ref_account(_ref_pd_cap); _env.ep().rpc_ep().apply(cap, [&] (Pd_session_component *pd) { if (pd) { _ref_pd.transfer_quota(pd->core_pd_cap(), _cap_quota); _ref_pd.transfer_quota(pd->core_pd_cap(), _ram_quota); } }); } Route resolve_session_request(Service::Name const &service_name, Session_label const &label) override { return Route { .service = _matching_service(service_name, label), .label = label, .diag = Session::Diag() }; } void announce_service(Service::Name const &service_name) override { if (_find_service(_child_services, service_name)) { Genode::warning(name(), ": service ", service_name, " is already registered"); return; } new (_alloc) Sandbox::Routed_service(_child_services, "target", *this, *this, _session_requester.id_space(), _child->session_factory(), service_name, *this); char server_config[4096]; try { Xml_generator xml(server_config, sizeof(server_config), "config", [&] () { _child_services.for_each([&] (Service &service) { xml.node("service", [&] () { xml.attribute("name", service_name); xml.node("default-policy", [&] () { xml.node("child", [&] () { xml.attribute("name", "target"); }); }); }); }); }); _server.apply_config(Xml_node(server_config)); } catch(Xml_generator::Buffer_exceeded &) { error("XML buffer for server configuration exceeded"); } _env.parent().announce(service_name.string()); } }; #endif /* _APP_CHILD_H_ */