diff --git a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc index 485581f64..cc4211400 100644 --- a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc +++ b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc @@ -109,6 +109,12 @@ void (*Genode::call_component_construct)(Genode::Env &) = &lx_hybrid_component_c */ void Genode::call_global_static_constructors() { } +Genode::size_t Component::stack_size() __attribute__((weak)); +Genode::size_t Component::stack_size() +{ + return 16UL * 1024 * sizeof(Genode::addr_t); +} + /* * Hybrid components are not allowed to implement legacy main(). This enables * us to hook in and bootstrap components as usual. diff --git a/repos/base-linux/src/test/lx_hybrid_ctors/main.cc b/repos/base-linux/src/test/lx_hybrid_ctors/main.cc index 09ef89722..95188ad90 100644 --- a/repos/base-linux/src/test/lx_hybrid_ctors/main.cc +++ b/repos/base-linux/src/test/lx_hybrid_ctors/main.cc @@ -44,9 +44,6 @@ static int exit_status; static void exit_on_suspended() { exit(exit_status); } -Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); } - - /* * Component implements classical main function in construct. */ diff --git a/repos/base-linux/src/test/lx_hybrid_errno/main.cc b/repos/base-linux/src/test/lx_hybrid_errno/main.cc index 663ca7131..b4417326b 100644 --- a/repos/base-linux/src/test/lx_hybrid_errno/main.cc +++ b/repos/base-linux/src/test/lx_hybrid_errno/main.cc @@ -46,9 +46,6 @@ static int exit_status; static void exit_on_suspended() { exit(exit_status); } -Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); } - - struct Unexpected_errno_change { }; /* diff --git a/repos/base-linux/src/test/lx_hybrid_exception/main.cc b/repos/base-linux/src/test/lx_hybrid_exception/main.cc index 9a955dcb8..eaa9f0aa6 100644 --- a/repos/base-linux/src/test/lx_hybrid_exception/main.cc +++ b/repos/base-linux/src/test/lx_hybrid_exception/main.cc @@ -27,9 +27,6 @@ static int exit_status; static void exit_on_suspended() { exit(exit_status); } -Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); } - - /* * Component implements classical main function in construct. */ diff --git a/repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc b/repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc index 5928e83d7..ea31290e3 100644 --- a/repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc +++ b/repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc @@ -53,9 +53,6 @@ static int exit_status; static void exit_on_suspended() { exit(exit_status); } -Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); } - - /* * Component implements classical main function in construct. */ diff --git a/repos/base-nova/src/test/platform/main.cc b/repos/base-nova/src/test/platform/main.cc index 0fbd1d833..0c337fcb6 100644 --- a/repos/base-nova/src/test/platform/main.cc +++ b/repos/base-nova/src/test/platform/main.cc @@ -600,7 +600,7 @@ class Greedy : public Genode::Thread { if (i % 8192 == 0) { /* transfer some quota to avoid tons of upgrade messages */ char const * const buf = "ram_quota=1280K"; - _env.parent().upgrade(_env.pd_session_cap(), buf); + _env.upgrade(Genode::Parent::Env::pd(), buf); log(Hex(i * 4096)); /* trigger some work to see quota in kernel decreasing */ // Nova::Rights rwx(true, true, true); diff --git a/repos/dde_bsd/src/lib/audio/bus.cc b/repos/dde_bsd/src/lib/audio/bus.cc index fb9435508..c0d81eca5 100644 --- a/repos/dde_bsd/src/lib/audio/bus.cc +++ b/repos/dde_bsd/src/lib/audio/bus.cc @@ -135,10 +135,7 @@ class Pci_driver : public Bsd::Bus_driver return Genode::retry( [&] () { return _pci.alloc_dma_buffer(size); }, [&] () { - char quota[32]; - Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd", - donate); - _env.parent().upgrade(_pci.cap(), quota); + _pci.upgrade_ram(donate); donate = donate * 2 > size ? 4096 : donate * 2; }); } @@ -161,9 +158,7 @@ class Pci_driver : public Bsd::Bus_driver int probe() { - char buf[32]; - Genode::snprintf(buf, sizeof(buf), "ram_quota=%u", 8192U); - _env.parent().upgrade(_pci.cap(), buf); + _pci.upgrade_ram(8*1024); /* * We hide ourself in the bus_dma_tag_t as well as @@ -404,10 +399,7 @@ extern "C" int pci_mapreg_map(struct pci_attach_args *pa, [&] () { device.config_write(Pci_driver::CMD, cmd, Platform::Device::ACCESS_16BIT); }, [&] () { - char quota[32]; - Genode::snprintf(quota, sizeof(quota), "ram_quota=%ld", - donate); - drv->env().parent().upgrade(drv->pci().cap(), quota); + drv->pci().upgrade_ram(donate); donate *= 2; }); diff --git a/repos/dde_ipxe/src/lib/dde_ipxe/dde_support.cc b/repos/dde_ipxe/src/lib/dde_ipxe/dde_support.cc index 3daef05e9..c2c30c453 100644 --- a/repos/dde_ipxe/src/lib/dde_ipxe/dde_support.cc +++ b/repos/dde_ipxe/src/lib/dde_ipxe/dde_support.cc @@ -177,10 +177,7 @@ struct Pci_driver Genode::retry( [&] () { client.config_write(devfn, val, _access_size(val)); } , [&] () { - char quota[32]; - Genode::snprintf(quota, sizeof(quota), "ram_quota=%ld", - donate); - Genode::env()->parent()->upgrade(_pci.cap(), quota); + _pci.upgrade_ram(donate); donate *= 2; }); } @@ -223,10 +220,7 @@ struct Pci_driver Ram_dataspace_capability ram_cap = Genode::retry( [&] () { return _pci.alloc_dma_buffer(size); }, [&] () { - char quota[32]; - Genode::snprintf(quota, sizeof(quota), "ram_quota=%ld", - donate); - Genode::env()->parent()->upgrade(_pci.cap(), quota); + _pci.upgrade_ram(donate); donate = donate * 2 > size ? 4096 : donate * 2; }); diff --git a/repos/dde_linux/src/include/lx_kit/internal/pci_dev.h b/repos/dde_linux/src/include/lx_kit/internal/pci_dev.h index 370c76319..16790777c 100644 --- a/repos/dde_linux/src/include/lx_kit/internal/pci_dev.h +++ b/repos/dde_linux/src/include/lx_kit/internal/pci_dev.h @@ -188,10 +188,7 @@ class Lx::Pci_dev : public pci_dev, public Lx_kit::List::Element Genode::retry( [&] () { _client.config_write(devfn, val, _access_size(val)); }, [&] () { - char quota[32]; - Genode::snprintf(quota, sizeof(quota), "ram_quota=%ld", - donate); - Genode::env()->parent()->upgrade(pci()->cap(), quota); + pci()->upgrade_ram(donate); donate *= 2; }); } @@ -230,9 +227,7 @@ void Lx::for_each_pci_device(FUNC const &func) * Functor that is called if the platform driver throws a * 'Out_of_metadata' exception. */ - auto handler = [&] () { - Genode::env()->parent()->upgrade(Lx::pci()->cap(), - "ram_quota=4096"); }; + auto handler = [&] () { Lx::pci()->upgrade_ram(4096); }; /* * Obtain first device, the operation may exceed the session quota. diff --git a/repos/dde_linux/src/lib/usb/spec/x86/pci_driver.cc b/repos/dde_linux/src/lib/usb/spec/x86/pci_driver.cc index 4aa598c43..bf6f099fc 100644 --- a/repos/dde_linux/src/lib/usb/spec/x86/pci_driver.cc +++ b/repos/dde_linux/src/lib/usb/spec/x86/pci_driver.cc @@ -60,9 +60,7 @@ class Pci_dev_list * Functor that is called if the platform driver throws a * 'Out_of_metadata' exception. */ - auto handler = [&] () { - Lx_kit::env().env().parent().upgrade(Lx::pci()->cap(), - "ram_quota=4096"); }; + auto handler = [&] () { Lx::pci()->upgrade_ram(4096); }; /* * Obtain first device, the operation may exceed the session quota. diff --git a/repos/dde_linux/src/lx_kit/pci.cc b/repos/dde_linux/src/lx_kit/pci.cc index a037fce21..68d3ac1e2 100644 --- a/repos/dde_linux/src/lx_kit/pci.cc +++ b/repos/dde_linux/src/lx_kit/pci.cc @@ -89,10 +89,7 @@ Lx::backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached) cap = retry( [&] () { return Lx::pci()->alloc_dma_buffer(size); }, [&] () { - char quota[32]; - Genode::snprintf(quota, sizeof(quota), "ram_quota=%ld", - donate); - Genode::env()->parent()->upgrade(Lx::pci()->cap(), quota); + Lx::pci()->upgrade_ram(donate); donate = donate * 2 > size ? 4096 : donate * 2; }); diff --git a/repos/gems/src/app/decorator/main.cc b/repos/gems/src/app/decorator/main.cc index 0210e332e..3b847e7d7 100644 --- a/repos/gems/src/app/decorator/main.cc +++ b/repos/gems/src/app/decorator/main.cc @@ -156,7 +156,7 @@ struct Decorator::Main : Window_factory_base Window(attribute(window_node, "id", 0UL), nitpicker, animator, config); } catch (Nitpicker::Session::Out_of_metadata) { Genode::log("Handle Out_of_metadata of nitpicker session - upgrade by 8K"); - Genode::env()->parent()->upgrade(nitpicker.cap(), "ram_quota=8192"); + nitpicker.upgrade_ram(8192); } } return 0; diff --git a/repos/hello_tutorial/run/hello.run b/repos/hello_tutorial/run/hello.run index 0dd52d8ca..d83c90907 100644 --- a/repos/hello_tutorial/run/hello.run +++ b/repos/hello_tutorial/run/hello.run @@ -35,4 +35,5 @@ build_boot_image { core init hello_client hello_server } append qemu_args " -nographic " +run_genode_until forever run_genode_until "hello test completed.*\n" 10 diff --git a/repos/libports/src/drivers/framebuffer/vesa/hw_emul.cc b/repos/libports/src/drivers/framebuffer/vesa/hw_emul.cc index 59cd23319..c91497c53 100644 --- a/repos/libports/src/drivers/framebuffer/vesa/hw_emul.cc +++ b/repos/libports/src/drivers/framebuffer/vesa/hw_emul.cc @@ -75,7 +75,7 @@ class Pci_card * Iterate through all accessible devices. */ Platform::Device_capability prev_device_cap, device_cap; - Genode::env()->parent()->upgrade(_pci_drv.cap(), "ram_quota=4096"); + _pci_drv.upgrade_ram(4096); for (device_cap = _pci_drv.first_device(); device_cap.valid(); device_cap = _pci_drv.next_device(prev_device_cap)) { diff --git a/repos/os/include/cli_monitor/child.h b/repos/os/include/cli_monitor/child.h index 413d32a6f..2a1136e3c 100644 --- a/repos/os/include/cli_monitor/child.h +++ b/repos/os/include/cli_monitor/child.h @@ -16,6 +16,7 @@ /* Genode includes */ #include +#include #include #include #include @@ -41,48 +42,29 @@ class Child_base : public Genode::Child_policy typedef Genode::size_t size_t; + typedef Genode::Registered Parent_service; + typedef Genode::Registry Parent_services; + private: Ram &_ram; Genode::Session_label const _label; + Binary_name const _binary_name; + + Genode::Ram_session_capability _ref_ram_cap; + Genode::Ram_session &_ref_ram; size_t _ram_quota; size_t _ram_limit; - struct Resources - { - Genode::Pd_connection pd; - Genode::Ram_connection ram; - Genode::Cpu_connection cpu; - - Resources(const char *label, Genode::size_t ram_quota) - : pd(label), ram(label), cpu(label) - { - if (ram_quota > DONATED_RAM_QUOTA) - ram_quota -= DONATED_RAM_QUOTA; - else - throw Quota_exceeded(); - ram.ref_account(Genode::env()->ram_session_cap()); - if (Genode::env()->ram_session()->transfer_quota(ram.cap(), ram_quota) != 0) - throw Quota_exceeded(); - } - } _resources; - - Genode::Child::Initial_thread _initial_thread { _resources.cpu, _resources.pd, - _label.string() }; - - Genode::Region_map_client _address_space { _resources.pd.address_space() }; - Genode::Service_registry _parent_services; - Genode::Rom_connection _binary_rom; + Parent_services _parent_services; enum { ENTRYPOINT_STACK_SIZE = 12*1024 }; Genode::Rpc_entrypoint _entrypoint; Init::Child_policy_enforce_labeling _labeling_policy; - Init::Child_policy_provide_rom_file _binary_policy; Genode::Child_policy_dynamic_rom_file _config_policy; - Genode::Child _child; /** * If set to true, immediately withdraw resources yielded by the child @@ -101,35 +83,39 @@ class Child_base : public Genode::Child_policy /* true if child is scheduled for destruction */ bool _exited = false; + Genode::Child _child; + public: + /** + * Constructor + * + * \param ref_ram used as reference account for the child'd RAM + * session and for allocating the backing store + * for the child's configuration + */ Child_base(Ram &ram, - char const *label, - char const *binary, - Genode::Cap_session &cap_session, + Name const &label, + Binary_name const &binary_name, + Genode::Pd_session &pd_session, + Genode::Ram_session &ref_ram, + Genode::Ram_session_capability ref_ram_cap, + Genode::Region_map &local_rm, Genode::size_t ram_quota, Genode::size_t ram_limit, Genode::Signal_context_capability yield_response_sig_cap, - Genode::Signal_context_capability exit_sig_cap, - Genode::Dataspace_capability ldso_ds) + Genode::Signal_context_capability exit_sig_cap) : _ram(ram), - _label(label), - _ram_quota(ram_quota), - _ram_limit(ram_limit), - _resources(_label.string(), _ram_quota), - _binary_rom(Genode::prefixed_label(Genode::Session_label(label), - Genode::Session_label(binary)).string()), - _entrypoint(&cap_session, ENTRYPOINT_STACK_SIZE, _label.string(), false), + _label(label), _binary_name(binary_name), + _ref_ram_cap(ref_ram_cap), _ref_ram(ref_ram), + _ram_quota(ram_quota), _ram_limit(ram_limit), + _entrypoint(&pd_session, ENTRYPOINT_STACK_SIZE, _label.string(), false), _labeling_policy(_label.string()), - _binary_policy("binary", _binary_rom.dataspace(), &_entrypoint), - _config_policy("config", _entrypoint, &_resources.ram), - _child(_binary_rom.dataspace(), ldso_ds, _resources.pd, _resources.pd, - _resources.ram, _resources.ram, _resources.cpu, _initial_thread, - *Genode::env()->rm_session(), _address_space, - _entrypoint, *this), + _config_policy("config", _entrypoint, &ref_ram), _yield_response_sigh_cap(yield_response_sig_cap), - _exit_sig_cap(exit_sig_cap) + _exit_sig_cap(exit_sig_cap), + _child(local_rm, _entrypoint, *this) { } Genode::Session_label label() const { return _label; } @@ -176,7 +162,7 @@ class Child_base : public Genode::Child_policy if (!amount) return; - _ram.withdraw_from(_resources.ram.cap(), amount); + _ram.withdraw_from(_child.ram_session_cap(), amount); _ram_quota -= amount; } @@ -187,12 +173,12 @@ class Child_base : public Genode::Child_policy */ void upgrade_ram_quota(size_t amount) { - _ram.transfer_to(_resources.ram.cap(), amount); + _ram.transfer_to(_child.ram_session_cap(), amount); _ram_quota += amount; /* wake up child if resource request is in flight */ size_t const req = requested_ram_quota(); - if (req && _resources.ram.avail() >= req) { + if (req && _child.ram().avail() >= req) { _child.notify_resource_avail(); /* clear request state */ @@ -258,9 +244,9 @@ class Child_base : public Genode::Child_policy { return Ram_status(_ram_quota, _ram_limit, - _ram_quota - _resources.ram.quota(), - _resources.ram.used(), - _resources.ram.avail(), + _ram_quota - _child.ram().quota(), + _child.ram().used(), + _child.ram().avail(), requested_ram_quota()); } @@ -274,36 +260,41 @@ class Child_base : public Genode::Child_policy ** Child_policy interface ** ****************************/ - const char *name() const { return _label.string(); } + Name name() const override { return _label.string(); } - Genode::Service *resolve_session_request(const char *service_name, - const char *args) + Genode::Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; } + Genode::Ram_session &ref_ram() override { return _ref_ram; } + + void init(Genode::Ram_session &session, Genode::Ram_session_capability cap) override { - Genode::Service *service = 0; - - /* check for binary file request */ - if ((service = _binary_policy.resolve_session_request(service_name, args))) - return service; - - /* check for config file request */ - if ((service = _config_policy.resolve_session_request(service_name, args))) - return service; - - /* fill parent service registry on demand */ - if (!(service = _parent_services.find(service_name))) { - service = new (Genode::env()->heap()) - Genode::Parent_service(service_name); - _parent_services.insert(service); - } - - /* return parent service */ - return service; + session.ref_account(_ref_ram_cap); + _ref_ram.transfer_quota(cap, _ram_quota); } - void filter_session_args(const char *service, - char *args, Genode::size_t args_len) + Genode::Service &resolve_session_request(Genode::Service::Name const &name, + Genode::Session_state::Args const &args) override { - _labeling_policy.filter_session_args(service, args, args_len); + Genode::Service *service = nullptr; + + /* check for config file request */ + if ((service = _config_policy.resolve_session_request(name.string(), args.string()))) + return *service; + + /* populate session-local parent service registry on demand */ + _parent_services.for_each([&] (Parent_service &s) { + if (s.name() == name) + service = &s; }); + + if (service) + return *service; + + return *new (Genode::env()->heap()) Parent_service(_parent_services, name); + } + + void filter_session_args(Genode::Service::Name const &service, + char *args, Genode::size_t args_len) override + { + _labeling_policy.filter_session_args(service.string(), args, args_len); } void yield_response() @@ -311,8 +302,8 @@ class Child_base : public Genode::Child_policy if (_withdraw_on_yield_response) { enum { RESERVE = 4*1024*1024 }; - size_t amount = _resources.ram.avail() < RESERVE - ? 0 : _resources.ram.avail() - RESERVE; + size_t amount = _child.ram().avail() < RESERVE + ? 0 : _child.ram().avail() - RESERVE; /* try to immediately withdraw freed-up resources */ try { withdraw_ram_quota(amount); } diff --git a/repos/os/include/file_system_session/connection.h b/repos/os/include/file_system_session/connection.h index a33430a59..699e1a1ff 100644 --- a/repos/os/include/file_system_session/connection.h +++ b/repos/os/include/file_system_session/connection.h @@ -112,7 +112,7 @@ struct File_system::Connection : File_system::Connection_base */ void upgrade_ram() { - Genode::env()->parent()->upgrade(cap(), "ram=8K"); + File_system::Connection_base::upgrade_ram(8*1024); } enum { UPGRADE_ATTEMPTS = 2 }; diff --git a/repos/os/include/nitpicker_session/connection.h b/repos/os/include/nitpicker_session/connection.h index 12dc28f49..11d3ae284 100644 --- a/repos/os/include/nitpicker_session/connection.h +++ b/repos/os/include/nitpicker_session/connection.h @@ -26,6 +26,10 @@ namespace Nitpicker { class Connection; } class Nitpicker::Connection : public Genode::Connection, public Session_client { + public: + + enum { RAM_QUOTA = 36*1024UL }; + private: Framebuffer::Session_client _framebuffer; @@ -48,8 +52,7 @@ class Nitpicker::Connection : public Genode::Connection, * Declare ram-quota donation */ using Genode::Arg_string; - enum { SESSION_METADATA = 36*1024 }; - Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", SESSION_METADATA); + Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", RAM_QUOTA); return session(parent, argbuf); } @@ -90,20 +93,12 @@ class Nitpicker::Connection : public Genode::Connection, void buffer(Framebuffer::Mode mode, bool use_alpha) { - enum { ARGBUF_SIZE = 128 }; - char argbuf[ARGBUF_SIZE]; - argbuf[0] = 0; - Genode::size_t const needed = ram_quota(mode, use_alpha); Genode::size_t const upgrade = needed > _session_quota ? needed - _session_quota : 0; - if (upgrade > 0) { - Genode::Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", - upgrade); - - Genode::env()->parent()->upgrade(cap(), argbuf); + this->upgrade_ram(upgrade); _session_quota += upgrade; } diff --git a/repos/os/include/nitpicker_session/nitpicker_session.h b/repos/os/include/nitpicker_session/nitpicker_session.h index b7d0ab5fa..81b3a6343 100644 --- a/repos/os/include/nitpicker_session/nitpicker_session.h +++ b/repos/os/include/nitpicker_session/nitpicker_session.h @@ -24,6 +24,7 @@ namespace Nitpicker { using Genode::size_t; + struct Session_client; struct View; typedef Genode::Capability View_capability; struct Session; @@ -37,6 +38,8 @@ struct Nitpicker::Session : Genode::Session { static const char *service_name() { return "Nitpicker"; } + typedef Session_client Client; + /** * Session-local view handle * diff --git a/repos/os/include/report_session/connection.h b/repos/os/include/report_session/connection.h index 574944202..5c1563ee5 100644 --- a/repos/os/include/report_session/connection.h +++ b/repos/os/include/report_session/connection.h @@ -22,6 +22,8 @@ namespace Report { struct Connection; } struct Report::Connection : Genode::Connection, Session_client { + enum { RAM_QUOTA = 4*4096 }; /* value used for 'Slave::Connection' */ + /** * Issue session request * diff --git a/repos/os/include/report_session/report_session.h b/repos/os/include/report_session/report_session.h index 0287a5bc7..f68490299 100644 --- a/repos/os/include/report_session/report_session.h +++ b/repos/os/include/report_session/report_session.h @@ -44,6 +44,7 @@ namespace Report { using Genode::size_t; struct Session; + struct Session_client; } @@ -51,6 +52,8 @@ struct Report::Session : Genode::Session { static const char *service_name() { return "Report"; } + typedef Session_client Client; + /** * Request the dataspace used to carry reports and responses */ diff --git a/repos/os/run/fault_detection.run b/repos/os/run/fault_detection.run index 516e11d43..d7ded0350 100644 --- a/repos/os/run/fault_detection.run +++ b/repos/os/run/fault_detection.run @@ -48,6 +48,12 @@ install_config { + + + + + + diff --git a/repos/os/run/loader.run b/repos/os/run/loader.run index c45c70a9b..0d96f9e7b 100644 --- a/repos/os/run/loader.run +++ b/repos/os/run/loader.run @@ -76,6 +76,11 @@ append config { + + + + + diff --git a/repos/os/run/resource_yield.run b/repos/os/run/resource_yield.run index a30a4ed8a..c41a18a54 100644 --- a/repos/os/run/resource_yield.run +++ b/repos/os/run/resource_yield.run @@ -25,6 +25,7 @@ install_config { + } diff --git a/repos/os/src/drivers/ahci/main.cc b/repos/os/src/drivers/ahci/main.cc index 557d30719..0c694ba76 100644 --- a/repos/os/src/drivers/ahci/main.cc +++ b/repos/os/src/drivers/ahci/main.cc @@ -135,7 +135,7 @@ class Block::Root_multiple_clients : public Root_component< ::Session_component> throw Root::Unavailable(); } - Factory *factory = new (&_alloc) Factory(num); + Block::Factory *factory = new (&_alloc) Block::Factory(num); ::Session_component *session = new (&_alloc) ::Session_component(*factory, _env.ep(), tx_buf_size); log("session opened at device ", num, " for '", label, "'"); @@ -145,8 +145,8 @@ class Block::Root_multiple_clients : public Root_component< ::Session_component> void _destroy_session(::Session_component *session) { Driver_factory &factory = session->factory(); - destroy(&_alloc, session); - destroy(&_alloc, &factory); + Genode::destroy(&_alloc, session); + Genode::destroy(&_alloc, &factory); } public: diff --git a/repos/os/src/drivers/ahci/spec/x86/platform.cc b/repos/os/src/drivers/ahci/spec/x86/platform.cc index 7c4752dd1..1260eb20e 100644 --- a/repos/os/src/drivers/ahci/spec/x86/platform.cc +++ b/repos/os/src/drivers/ahci/spec/x86/platform.cc @@ -46,7 +46,7 @@ struct X86_hba : Platform::Hba pci_device_cap = retry( [&] () { return pci.next_device(pci_device_cap, AHCI_DEVICE, CLASS_MASK); }, - [&] () { env.parent().upgrade(pci.cap(), "ram_quota=4096"); }); + [&] () { pci.upgrade_ram(4096); }); if (!pci_device_cap.valid()) { Genode::error("no AHCI controller found"); @@ -102,10 +102,7 @@ struct X86_hba : Platform::Hba Genode::retry( [&] () { pci_device->config_write(op, cmd, width); }, [&] () { - char quota[32]; - Genode::snprintf(quota, sizeof(quota), "ram_quota=%ld", - donate); - env.parent().upgrade(pci.cap(), quota); + pci.upgrade_ram(donate); donate *= 2; }); } @@ -134,9 +131,7 @@ struct X86_hba : Platform::Hba return retry( [&] () { return pci.alloc_dma_buffer(size); }, [&] () { - char quota[32]; - snprintf(quota, sizeof(quota), "ram_quota=%ld", donate); - env.parent().upgrade(pci.cap(), quota); + pci.upgrade_ram(donate); donate = donate * 2 > size ? 4096 : donate * 2; }); } diff --git a/repos/os/src/drivers/audio/spec/linux/main.cc b/repos/os/src/drivers/audio/spec/linux/main.cc index 8d06219d9..ca16b6985 100644 --- a/repos/os/src/drivers/audio/spec/linux/main.cc +++ b/repos/os/src/drivers/audio/spec/linux/main.cc @@ -305,7 +305,4 @@ struct Audio_out::Main ** Component ** ***************/ -namespace Component { - Genode::size_t stack_size() { return 2*1024*sizeof(addr_t); } - void construct(Genode::Env &env) { static Audio_out::Main main(env); } -} +void Component::construct(Genode::Env &env) { static Audio_out::Main main(env); } diff --git a/repos/os/src/drivers/framebuffer/spec/sdl/fb_sdl.cc b/repos/os/src/drivers/framebuffer/spec/sdl/fb_sdl.cc index 8d526181b..c963f4ab1 100644 --- a/repos/os/src/drivers/framebuffer/spec/sdl/fb_sdl.cc +++ b/repos/os/src/drivers/framebuffer/spec/sdl/fb_sdl.cc @@ -214,5 +214,4 @@ struct Main }; -Genode::size_t Component::stack_size() { return 4*1024*sizeof(long); } void Component::construct(Genode::Env &env) { static Main inst(env); } diff --git a/repos/os/src/drivers/nic/spec/gem/cadence_gem.h b/repos/os/src/drivers/nic/spec/gem/cadence_gem.h index d9e8c24e0..cdb20af9f 100644 --- a/repos/os/src/drivers/nic/spec/gem/cadence_gem.h +++ b/repos/os/src/drivers/nic/spec/gem/cadence_gem.h @@ -481,6 +481,8 @@ namespace Genode _deinit(); } + using Nic::Session_component::cap; + void phy_write(const uint8_t phyaddr, const uint8_t regnum, const uint16_t data) { diff --git a/repos/os/src/drivers/platform/spec/x86/device_pd.h b/repos/os/src/drivers/platform/spec/x86/device_pd.h index f3e0bee28..c3cc7ae2e 100644 --- a/repos/os/src/drivers/platform/spec/x86/device_pd.h +++ b/repos/os/src/drivers/platform/spec/x86/device_pd.h @@ -15,71 +15,32 @@ #include -enum { STACK_SIZE = 2 * sizeof(void *) * 1024 }; +enum { STACK_SIZE = 4 * sizeof(void *) * 1024 }; namespace Platform { class Device_pd_policy; } -class Platform::Device_pd_policy : public Genode::Slave_policy +class Platform::Device_pd_policy : public Genode::Slave::Policy { - private: - - Genode::Root_capability _cap; - Genode::Lock _lock; - - Genode::Ram_session_capability _ram_ref_cap; - Genode::Slave _device_pd_slave; - protected: - char const **_permitted_services() const + char const **_permitted_services() const override { - static char const *permitted_services[] = { "LOG", "CAP", "RM", 0 }; + static char const *permitted_services[] = { + "RAM", "PD", "CPU", "LOG", "ROM", 0 }; return permitted_services; }; public: - Device_pd_policy(Genode::Rpc_entrypoint &slave_ep, + Device_pd_policy(Genode::Rpc_entrypoint &slave_ep, + Genode::Region_map &local_rm, Genode::Ram_session_capability ram_ref_cap, - Genode::addr_t device_pd_ram_quota, - const char * label) + Genode::size_t ram_quota, + Genode::Session_label const &label) : - Slave_policy(label, slave_ep, nullptr, "device_pd"), - _lock(Genode::Lock::LOCKED), - _ram_ref_cap(ram_ref_cap), - _device_pd_slave(slave_ep, *this, device_pd_ram_quota, ram_ref_cap) + Genode::Slave::Policy(label, "device_pd", slave_ep, local_rm, + ram_ref_cap, ram_quota) { } - - bool announce_service(const char *service_name, - Genode::Root_capability root, - Genode::Allocator *alloc, - Genode::Server *server) - { - /* wait for 'platform_drv' to announce the DEVICE_PD service */ - if (Genode::strcmp(service_name, "DEVICE_PD")) - return false; - - _cap = root; - - _lock.unlock(); - - return true; - } - - Genode::Root_capability root() { - if (!_cap.valid()) - _lock.lock(); - return _cap; - } - - Genode::Ram_connection &ram_slave() { return _device_pd_slave.ram(); } - - /** - * Override struct Genode::Child_policy::ref_ram_cap with our ram cap - */ - Genode::Ram_session_capability ref_ram_cap() const override { - return _ram_ref_cap; } - }; diff --git a/repos/os/src/drivers/platform/spec/x86/device_pd/main.cc b/repos/os/src/drivers/platform/spec/x86/device_pd/main.cc index eb20d00e3..bf0c56771 100644 --- a/repos/os/src/drivers/platform/spec/x86/device_pd/main.cc +++ b/repos/os/src/drivers/platform/spec/x86/device_pd/main.cc @@ -62,11 +62,8 @@ struct Expanding_region_map_client : Genode::Region_map_client if (Genode::env()->ram_session()->avail() < UPGRADE_QUOTA) throw; - char buf[32]; - Genode::snprintf(buf, sizeof(buf), "ram_quota=%u", - UPGRADE_QUOTA); - - _env.parent().upgrade(_env.pd_session_cap(), buf); + Genode::String<32> arg("ram_quota=", (unsigned)UPGRADE_QUOTA); + _env.upgrade(Genode::Parent::Env::pd(), arg.string()); } ); } diff --git a/repos/os/src/drivers/platform/spec/x86/nonpci_devices.cc b/repos/os/src/drivers/platform/spec/x86/nonpci_devices.cc index 817ce4c18..2901c42f1 100644 --- a/repos/os/src/drivers/platform/spec/x86/nonpci_devices.cc +++ b/repos/os/src/drivers/platform/spec/x86/nonpci_devices.cc @@ -29,24 +29,24 @@ class Nonpci::Ps2 : public Platform::Device_component REG_STATUS = 0x64, }; + Genode::Rpc_entrypoint &_ep; Platform::Irq_session_component _irq_mouse; Genode::Io_port_connection _data; Genode::Io_port_connection _status; public: - Ps2(Genode::Rpc_entrypoint * ep, Platform::Session_component * session) + Ps2(Genode::Rpc_entrypoint &ep, Platform::Session_component &session) : Platform::Device_component(ep, session, IRQ_KEYBOARD), + _ep(ep), _irq_mouse(IRQ_MOUSE, ~0UL), _data(REG_DATA, ACCESS_WIDTH), _status(REG_STATUS, ACCESS_WIDTH) { - ep->manage(&_irq_mouse); + _ep.manage(&_irq_mouse); } - ~Ps2() { - ep()->dissolve(&_irq_mouse); - } + ~Ps2() { _ep.dissolve(&_irq_mouse); } Genode::Irq_session_capability irq(Genode::uint8_t virt_irq) override { @@ -97,7 +97,7 @@ class Nonpci::Pit : public Platform::Device_component public: - Pit(Genode::Rpc_entrypoint * ep, Platform::Session_component * session) + Pit(Genode::Rpc_entrypoint &ep, Platform::Session_component &session) : Platform::Device_component(ep, session, IRQ_PIT), _ports(PIT_PORT, PORTS_WIDTH) @@ -147,17 +147,17 @@ Platform::Device_capability Platform::Session_component::device(String const &na switch(devices_i) { case 0: - dev = new (_md_alloc) Nonpci::Ps2(_ep, this); + dev = new (_md_alloc) Nonpci::Ps2(_ep, *this); break; case 1: - dev = new (_md_alloc) Nonpci::Pit(_ep, this); + dev = new (_md_alloc) Nonpci::Pit(_ep, *this); break; default: return Device_capability(); } _device_list.insert(dev); - return _ep->manage(dev); + return _ep.manage(dev); } catch (Genode::Allocator::Out_of_memory) { throw Out_of_metadata(); } catch (Genode::Parent::Service_denied) { diff --git a/repos/os/src/drivers/platform/spec/x86/pci_device.cc b/repos/os/src/drivers/platform/spec/x86/pci_device.cc index 4508229c3..e2af26d76 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_device.cc +++ b/repos/os/src/drivers/platform/spec/x86/pci_device.cc @@ -73,6 +73,7 @@ Genode::Io_mem_session_capability Platform::Device_component::io_mem(Genode::uin _io_mem[i].insert(io_mem); return io_mem->cap(); } catch (Genode::Allocator::Out_of_memory) { + Genode::error("Quota_exceeded in Device_component::io_mem"); throw Quota_exceeded(); } catch (...) { return Genode::Io_mem_session_capability(); @@ -116,9 +117,9 @@ void Platform::Device_component::config_write(unsigned char address, } /* assign device to device_pd */ - if (address == PCI_CMD_REG && value & PCI_CMD_DMA && _session) { + if (address == PCI_CMD_REG && value & PCI_CMD_DMA) { try { - _session->assign_device(this); + _session.assign_device(this); } catch (Platform::Session::Out_of_metadata) { throw Quota_exceeded(); } catch (...) { @@ -145,14 +146,14 @@ Genode::Irq_session_capability Platform::Device_component::irq(Genode::uint8_t i _irq_session = construct_at(_mem_irq_component, _irq_line, ~0UL); - _ep->manage(_irq_session); + _ep.manage(_irq_session); return _irq_session->cap(); } _irq_session = construct_at(_mem_irq_component, _configure_irq(_irq_line), - (!_session->msi_usage() || !_msi_cap()) ? ~0UL : _config_space); - _ep->manage(_irq_session); + (!_session.msi_usage() || !_msi_cap()) ? ~0UL : _config_space); + _ep.manage(_irq_session); Genode::uint16_t msi_cap = _msi_cap(); diff --git a/repos/os/src/drivers/platform/spec/x86/pci_device_component.h b/repos/os/src/drivers/platform/spec/x86/pci_device_component.h index e241b9116..3ce93ace9 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_device_component.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_device_component.h @@ -37,10 +37,10 @@ class Platform::Device_component : public Genode::Rpc_object, Device_config _device_config; Genode::addr_t _config_space; Config_access _config_access; - Genode::Rpc_entrypoint *_ep; - Platform::Session_component *_session; + Genode::Rpc_entrypoint &_ep; + Platform::Session_component &_session; unsigned short _irq_line; - Irq_session_component *_irq_session; + Irq_session_component *_irq_session = nullptr; Genode::Lazy_volatile_object _io_mem_config_extended; @@ -177,28 +177,22 @@ class Platform::Device_component : public Genode::Rpc_object, Platform::Device::ACCESS_16BIT); } - - protected: - - Genode::Rpc_entrypoint * ep() { return _ep; } - public: /** * Constructor */ Device_component(Device_config device_config, Genode::addr_t addr, - Genode::Rpc_entrypoint *ep, - Platform::Session_component * session, - Genode::Allocator * md_alloc) + Genode::Rpc_entrypoint &ep, + Platform::Session_component &session, + Genode::Allocator &md_alloc) : _device_config(device_config), _config_space(addr), _ep(ep), _session(session), _irq_line(_device_config.read(&_config_access, PCI_IRQ_LINE, Platform::Device::ACCESS_8BIT)), - _irq_session(nullptr), - _slab_ioport(md_alloc, &_slab_ioport_block_data), - _slab_iomem(md_alloc, &_slab_iomem_block_data) + _slab_ioport(&md_alloc, &_slab_ioport_block_data), + _slab_iomem(&md_alloc, &_slab_iomem_block_data) { for (unsigned i = 0; i < Device::NUM_RESOURCES; i++) { _io_port_conn[i] = nullptr; @@ -210,15 +204,14 @@ class Platform::Device_component : public Genode::Rpc_object, /** * Constructor for non PCI devices */ - Device_component(Genode::Rpc_entrypoint * ep, - Platform::Session_component * session, unsigned irq) + Device_component(Genode::Rpc_entrypoint &ep, + Platform::Session_component &session, unsigned irq) : _config_space(~0UL), _ep(ep), _session(session), _irq_line(irq), - _irq_session(nullptr), - _slab_ioport(0, &_slab_ioport_block_data), - _slab_iomem(0, &_slab_iomem_block_data) + _slab_ioport(nullptr, &_slab_ioport_block_data), + _slab_iomem(nullptr, &_slab_iomem_block_data) { for (unsigned i = 0; i < Device::NUM_RESOURCES; i++) _io_port_conn[i] = nullptr; @@ -230,7 +223,7 @@ class Platform::Device_component : public Genode::Rpc_object, ~Device_component() { if (_irq_session) { - _ep->dissolve(_irq_session); + _ep.dissolve(_irq_session); _irq_session->~Irq_session(); } diff --git a/repos/os/src/drivers/platform/spec/x86/pci_device_pd_ipc.h b/repos/os/src/drivers/platform/spec/x86/pci_device_pd_ipc.h index 2083b5b70..9288cd0d2 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_device_pd_ipc.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_device_pd_ipc.h @@ -13,6 +13,7 @@ #pragma once +#include #include #include @@ -21,6 +22,7 @@ namespace Platform { struct Device_pd; struct Device_pd_client; + struct Device_pd_connection; struct Device_pd_component; } @@ -28,6 +30,8 @@ struct Platform::Device_pd : Genode::Session { static const char *service_name() { return "DEVICE_PD"; } + typedef Device_pd_client Client; + GENODE_RPC_THROW(Rpc_attach_dma_mem, void, attach_dma_mem, GENODE_TYPE_LIST(Genode::Rm_session::Out_of_metadata), Genode::Dataspace_capability); @@ -54,6 +58,17 @@ struct Platform::Device_pd_client : Genode::Rpc_client } }; +struct Platform::Device_pd_connection : Genode::Connection, Device_pd_client +{ + enum { RAM_QUOTA = 0UL }; + + Device_pd_connection(Genode::Capability cap) + : + Genode::Connection(cap), + Device_pd_client(cap) + { } +}; + struct Platform::Device_pd_component : Genode::Rpc_object { diff --git a/repos/os/src/drivers/platform/spec/x86/pci_session_component.h b/repos/os/src/drivers/platform/spec/x86/pci_session_component.h index 4732eef35..a96eb2fe2 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_session_component.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_session_component.h @@ -17,11 +17,8 @@ #include #include #include -#include - #include #include -#include #include #include @@ -123,455 +120,324 @@ class Platform::Rmrr : public Genode::List::Element } }; -namespace Platform { - class Session_component : public Genode::Rpc_object - { - private: +namespace Platform { class Session_component; } - Genode::Rpc_entrypoint *_ep; - Genode::Allocator_guard _md_alloc; - Genode::List _device_list; - Genode::Rpc_entrypoint &_device_pd_ep; - Genode::Session_label _label; +class Platform::Session_component : public Genode::Rpc_object +{ + private: - struct Resources { - Genode::Ram_connection _ram; - Genode::List _ram_caps; - Genode::Tslab _ram_caps_slab; + Genode::Rpc_entrypoint &_ep; + Genode::Rpc_entrypoint &_device_pd_ep; + Genode::Ram_session &_env_ram; + Genode::Ram_session_capability _env_ram_cap; + Genode::Region_map &_local_rm; + Genode::Allocator_guard _md_alloc; + Genode::Session_label const _label; + Genode::Session_policy const _policy { _label }; + Genode::List _device_list; + bool _no_device_pd = false; - Resources(Genode::Allocator_guard &md_alloc, Genode::Session_label &label) - : - /* restrict physical address to 3G on 32bit, 4G on 64bit */ - _ram(label.string(), 0, (sizeof(void *) == 4) - ? 0xc0000000UL : 0x100000000ULL), - _ram_caps_slab(&md_alloc) - { - /* associate _ram session with platform_drv _ram session */ - _ram.ref_account(Genode::env()->ram_session_cap()); + /** + * Registry of RAM dataspaces allocated by the session + */ + Genode::List _ram_caps; - /* - * Equip RAM session with initial quota to account for - * core-internal allocation meta-data overhead. - */ - enum { OVERHEAD = 4096 }; - Genode::env()->ram_session()->transfer_quota(_ram, OVERHEAD); - } + Genode::Tslab _ram_caps_slab { &_md_alloc }; - Genode::Ram_connection &ram() { return _ram; } + void _insert(Genode::Ram_dataspace_capability cap) + { + _ram_caps.insert(new (_ram_caps_slab) Platform::Ram_dataspace(cap)); + } - void insert(Genode::Ram_dataspace_capability cap) { - _ram_caps.insert(new (_ram_caps_slab) Platform::Ram_dataspace(cap)); } + bool _remove(Genode::Ram_dataspace_capability cap) + { + for (Platform::Ram_dataspace *ds = _ram_caps.first(); ds; + ds = ds->next()) + if (ds->match(cap)) + return true; + return false; + } - bool remove(Genode::Ram_dataspace_capability cap) { - for (Platform::Ram_dataspace *ds = _ram_caps.first(); ds; - ds = ds->next()) - if (ds->match(cap)) + /** + * Session-local RAM account + * + * Restrict physical address to 3G on 32bit + */ + Genode::Ram_connection _ram { + _label.string(), 0, (sizeof(void *) == 4) ? 0xc0000000UL : 0x100000000UL }; + + /* + * Associate session RAM session with platform_drv _ram session and + * equip RAM session with initial quota to account for core-internal + * allocation meta-data overhead. + */ + void _init_ram() + { + _ram.ref_account(_env_ram_cap); + + enum { OVERHEAD = 4096 }; + if (_env_ram.transfer_quota(_ram, OVERHEAD) != 0) + throw Out_of_metadata(); + } + + bool const _ram_initialized = (_init_ram(), true); + + /** + * Deduce specified amount of quota from an allocator guard, or throw + * an 'Out_of_metadata' exception if the guard's quota is depleted. + */ + struct Quota_reservation + { + Genode::Allocator_guard &guard; + + Genode::size_t const amount; + + Quota_reservation(Genode::Allocator_guard &guard, Genode::size_t amount) + : guard(guard), amount(amount) + { + if (!guard.withdraw(amount)) + throw Out_of_metadata(); + } + + ~Quota_reservation() { guard.upgrade(amount); } + }; + + class Device_pd + { + private: + + enum { RAM_QUOTA = 190 * 4096 }; + + Quota_reservation const _reservation; + Device_pd_policy _policy; + Genode::Child _child; + Genode::Slave::Connection _connection; + + public: + + /** + * Constructor + * + * \throw Out_of_metadata session RAM does not suffice + * for creating device PD + * \throw Process_startup_failed by 'Child' + * \throw Parent::Service_denied by 'Slave::Connection' + */ + Device_pd(Genode::Region_map &local_rm, + Genode::Rpc_entrypoint &ep, + Genode::Allocator_guard &guard, + Genode::Ram_session_capability ref_ram, + Genode::Session_label const &label) + try : + _reservation(guard, RAM_QUOTA), + _policy(ep, local_rm, ref_ram, RAM_QUOTA, label), + _child(local_rm, ep, _policy), + _connection(_policy, Genode::Slave::Args()) + { } + /* thrown by 'Quota_reservation' */ + catch (Out_of_metadata) { throw; } + /* thrown by 'Device_pd_policy' or 'Child' */ + catch (Genode::Ram_session::Alloc_failed) { throw Out_of_metadata(); } + /* throw by 'Slave::Connection' */ + catch (Genode::Parent::Quota_exceeded) { throw Out_of_metadata(); } + + Device_pd_client &session() { return _connection; } + + Genode::Ram_session_capability ram_session_cap() { + return _child.ram_session_cap(); } + }; + + Device_pd *_device_pd = nullptr; + + /** + * Free device PD at session destruction + */ + struct Device_pd_guard + { + Session_component &session; + + ~Device_pd_guard() { + if (session._device_pd) + Genode::destroy(session._md_alloc, session._device_pd); } + + } _device_pd_guard { *this }; + + /** + * Attempt to initialize device PD + * + * \throw Out_of_metadata session quota does not suffice to spawn the + * device PD + */ + void _try_init_device_pd() + { + if (_device_pd || _no_device_pd) + return; + + try { + _device_pd = new (_md_alloc) + Device_pd(_local_rm, _device_pd_ep, _md_alloc, + _env_ram_cap, _label); + } + + /* thrown by '_md_alloc' */ + catch (Genode::Allocator::Out_of_memory) { throw Out_of_metadata(); } + + /* thrown by 'Device_pd' */ + catch (Out_of_metadata) { throw; } + + catch (...) { + Genode::warning("PCI device protection domain for IOMMU support " + "is not available"); + _no_device_pd = true; + } + } + + enum { MAX_PCI_DEVICES = Device_config::MAX_BUSES * + Device_config::MAX_DEVICES * + Device_config::MAX_FUNCTIONS }; + + static Genode::Bit_array bdf_in_use; + + + /** + * Scan PCI buses for a device + * + * \param bus start scanning at bus number + * \param device start scanning at device number + * \param function start scanning at function number + * \param out_device_config device config information of the + * found device + * \param config_access interface for accessing the PCI + * configuration + * space + * + * \retval true device was found + * \retval false no device was found + */ + bool _find_next(int bus, int device, int function, + Device_config *out_device_config, + Config_access *config_access) + { + for (; bus < Device_config::MAX_BUSES; bus++) { + if (!bus_valid(bus)) + continue; + + for (; device < Device_config::MAX_DEVICES; device++) { + for (; function < Device_config::MAX_FUNCTIONS; function++) { + + /* read config space */ + Device_config config(bus, device, function, config_access); + + if (config.valid()) { + *out_device_config = config; return true; - return false; - } - - } _resources; - - struct Devicepd { - Device_pd_policy *policy; - Device_pd_client child; - Genode::Allocator_guard &_md_alloc; - - enum { DEVICE_PD_RAM_QUOTA = 180 * 4096 }; - - Devicepd (Genode::Rpc_entrypoint &ep, - Genode::Allocator_guard &md_alloc, - Genode::Ram_session_capability ram_ref_cap, - const char * label) - : - policy(nullptr), - child(Genode::reinterpret_cap_cast(Genode::Native_capability())), - _md_alloc(md_alloc) - { - if (!md_alloc.withdraw(DEVICE_PD_RAM_QUOTA)) - throw Out_of_metadata(); - - if (Genode::env()->ram_session()->transfer_quota(ram_ref_cap, DEVICE_PD_RAM_QUOTA)) { - Genode::error("Transferring quota for device pd failed"); - md_alloc.upgrade(DEVICE_PD_RAM_QUOTA); - throw Platform::Session::Fatal(); - } - - try { - policy = new (md_alloc) Device_pd_policy(ep, ram_ref_cap, DEVICE_PD_RAM_QUOTA, label); - - using Genode::Session_capability; - using Genode::Affinity; - - Session_capability session = Genode::Root_client(policy->root()).session("", Affinity()); - child = Device_pd_client(Genode::reinterpret_cap_cast(session)); - } catch (Genode::Rom_connection::Rom_connection_failed) { - Genode::warning("PCI device protection domain for IOMMU support " - "is not available"); - - if (policy) { - destroy(md_alloc, policy); - policy = nullptr; } - - md_alloc.upgrade(DEVICE_PD_RAM_QUOTA); - } catch (Genode::Allocator::Out_of_memory) { - md_alloc.upgrade(DEVICE_PD_RAM_QUOTA); - throw Out_of_metadata(); - } catch(...) { - Genode::error("unknown exception"); - md_alloc.upgrade(DEVICE_PD_RAM_QUOTA); - throw Platform::Session::Fatal(); } + function = 0; /* init value for next device */ } + device = 0; /* init value for next bus */ + } + return false; + } - ~Devicepd() { - if (!policy) - return; + /** + * List containing extended PCI config space information + */ + static Genode::List &config_space_list() { + static Genode::List config_space; + return config_space; + } - destroy(_md_alloc, policy); - _md_alloc.upgrade(DEVICE_PD_RAM_QUOTA); - } + /** + * Find for a given PCI device described by the bus:dev:func triple + * the corresponding extended 4K PCI config space address. + * A io mem dataspace is created and returned. + */ + Genode::addr_t + lookup_config_space(Genode::uint16_t const bdf) + { + using namespace Genode; - bool valid() { return policy && policy->root().valid() && child.valid(); } + addr_t config_space = ~0UL; /* invalid */ + + Config_space *e = config_space_list().first(); + for (; e && (config_space == ~0UL); e = e->next()) + config_space = e->lookup_config_space(bdf); + + return config_space; + } + + /* + * List of aliases for PCI Class/Subclas/Prog I/F triple used + * by xml config for this platform driver + */ + unsigned class_subclass_prog(const char * name) { + using namespace Genode; + + static struct { + const char * alias; + uint8_t pci_class, pci_subclass, pci_progif; + } const aliases [] = { + { "AHCI" , 0x1, 0x06, 0x0}, + { "ALL" , 0x0, 0x00, 0x0}, + { "AUDIO" , 0x4, 0x01, 0x0}, + { "ETHERNET" , 0x2, 0x00, 0x0}, + { "HDAUDIO" , 0x4, 0x03, 0x0}, + { "USB" , 0xc, 0x03, 0x0}, + { "VGA" , 0x3, 0x00, 0x0}, + { "WIFI" , 0x2, 0x80, 0x0}, + { "ISABRIDGE", 0x6, 0x01, 0x0} }; - Genode::Session_policy _policy; + for (unsigned i = 0; i < sizeof(aliases) / sizeof(aliases[0]); i++) { + if (strcmp(aliases[i].alias, name)) + continue; - Genode::Lazy_volatile_object _device_pd; - - enum { MAX_PCI_DEVICES = Device_config::MAX_BUSES * - Device_config::MAX_DEVICES * - Device_config::MAX_FUNCTIONS }; - - static Genode::Bit_array bdf_in_use; - - - /** - * Scan PCI buses for a device - * - * \param bus start scanning at bus number - * \param device start scanning at device number - * \param function start scanning at function number - * \param out_device_config device config information of the - * found device - * \param config_access interface for accessing the PCI - * configuration - * space - * - * \retval true device was found - * \retval false no device was found - */ - bool _find_next(int bus, int device, int function, - Device_config *out_device_config, - Config_access *config_access) - { - for (; bus < Device_config::MAX_BUSES; bus++) { - if (!bus_valid(bus)) - continue; - - for (; device < Device_config::MAX_DEVICES; device++) { - for (; function < Device_config::MAX_FUNCTIONS; function++) { - - /* read config space */ - Device_config config(bus, device, function, config_access); - - if (config.valid()) { - *out_device_config = config; - return true; - } - } - function = 0; /* init value for next device */ - } - device = 0; /* init value for next bus */ - } - return false; + return 0U | aliases[i].pci_class << 16 | + aliases[i].pci_subclass << 8 | + aliases[i].pci_progif; } - /** - * List containing extended PCI config space information - */ - static Genode::List &config_space_list() { - static Genode::List config_space; - return config_space; - } + return ~0U; + } - /** - * Find for a given PCI device described by the bus:dev:func triple - * the corresponding extended 4K PCI config space address. - * A io mem dataspace is created and returned. - */ - Genode::addr_t - lookup_config_space(Genode::uint16_t const bdf) - { - using namespace Genode; + /** + * Check device usage according to session policy + */ + bool permit_device(const char * name) + { + using namespace Genode; - addr_t config_space = ~0UL; /* invalid */ - - Config_space *e = config_space_list().first(); - for (; e && (config_space == ~0UL); e = e->next()) - config_space = e->lookup_config_space(bdf); - - return config_space; - } - - /* - * List of aliases for PCI Class/Subclas/Prog I/F triple used - * by xml config for this platform driver - */ - unsigned class_subclass_prog(const char * name) { - using namespace Genode; - - static struct { - const char * alias; - uint8_t pci_class, pci_subclass, pci_progif; - } const aliases [] = { - { "AHCI" , 0x1, 0x06, 0x0}, - { "ALL" , 0x0, 0x00, 0x0}, - { "AUDIO" , 0x4, 0x01, 0x0}, - { "ETHERNET" , 0x2, 0x00, 0x0}, - { "HDAUDIO" , 0x4, 0x03, 0x0}, - { "USB" , 0xc, 0x03, 0x0}, - { "VGA" , 0x3, 0x00, 0x0}, - { "WIFI" , 0x2, 0x80, 0x0}, - { "ISABRIDGE", 0x6, 0x01, 0x0} - }; - - for (unsigned i = 0; i < sizeof(aliases) / sizeof(aliases[0]); i++) { - if (strcmp(aliases[i].alias, name)) - continue; - - return 0U | aliases[i].pci_class << 16 | - aliases[i].pci_subclass << 8 | - aliases[i].pci_progif; - } - - return ~0U; - } - - /** - * Check device usage according to session policy - */ - bool permit_device(const char * name) - { - using namespace Genode; - - try { - _policy.for_each_sub_node("device", [&] (Xml_node dev) { - try { - /* enforce restriction based on name name */ - char policy_name[8]; - dev.attribute("name").value(policy_name, - sizeof(policy_name)); - - if (!strcmp(policy_name, name)) - /* found identical match - permit access */ - throw true; - - } catch (Xml_attribute::Nonexistent_attribute) { } - }); - } catch (bool result) { return result; } - - return false; - } - - /** - * Check according session policy device usage - */ - bool permit_device(Genode::uint8_t b, Genode::uint8_t d, - Genode::uint8_t f, unsigned class_code) - { - using namespace Genode; - - try { - _policy.for_each_sub_node("pci", [&] (Xml_node node) { - try { - unsigned bus, device, function; - - node.attribute("bus").value(&bus); - node.attribute("device").value(&device); - node.attribute("function").value(&function); - - if (b == bus && d == device && f == function) - throw true; - - return; - } catch (Xml_attribute::Nonexistent_attribute) { } - - /* enforce restriction based upon classes */ - unsigned class_sub_prog = 0; - - try { - char alias_class[32]; - node.attribute("class").value(alias_class, - sizeof(alias_class)); - - class_sub_prog = class_subclass_prog(alias_class); - } catch (Xml_attribute::Nonexistent_attribute) { - return; - } - - enum { DONT_CHECK_PROGIF = 8 }; - /* if class/subclass don't match - deny */ - if (class_sub_prog && (class_sub_prog ^ class_code) >> DONT_CHECK_PROGIF) - return; - - /* if this bdf is used by some policy - deny */ - if (find_dev_in_policy(b, d, f)) - return; - - throw true; - }); - } catch (bool result) { return result; } - - return false; - } - - /** - * Lookup a given device name. - */ - bool find_dev_in_policy(const char * dev_name, bool once = true) - { - using namespace Genode; - - try { - config()->xml_node().for_each_sub_node("policy", [&] (Xml_node policy) { - policy.for_each_sub_node("device", [&] (Xml_node device) { - try { - /* device attribute from policy node */ - char policy_device[8]; - device.attribute("name").value(policy_device, sizeof(policy_device)); - - if (!strcmp(policy_device, dev_name)) { - if (once) - throw true; - once = true; - } - } catch (Xml_node::Nonexistent_attribute) { } - }); - }); - } catch (bool result) { return result; } - - return false; - } - - /** - * Lookup a given device name. - */ - bool find_dev_in_policy(Genode::uint8_t b, Genode::uint8_t d, - Genode::uint8_t f, bool once = true) - { - using namespace Genode; - - try { - Xml_node xml(config()->xml_node()); - xml.for_each_sub_node("policy", [&] (Xml_node policy) { - policy.for_each_sub_node("pci", [&] (Xml_node node) { - try { - unsigned bus, device, function; - - node.attribute("bus").value(&bus); - node.attribute("device").value(&device); - node.attribute("function").value(&function); - - if (b == bus && d == device && f == function) { - if (once) - throw true; - once = true; - } - } catch (Xml_node::Nonexistent_attribute) { } - }); - }); - } catch (bool result) { return result; } - - return false; - } - - public: - - /** - * Constructor - */ - Session_component(Genode::Rpc_entrypoint *ep, - Genode::Allocator *md_alloc, - const char *args, - Genode::Rpc_entrypoint &device_pd_ep) - : - _ep(ep), - _md_alloc(md_alloc, Genode::Arg_string::find_arg(args, "ram_quota").long_value(0)), - _device_pd_ep(device_pd_ep), - _label(Genode::label_from_args(args)), - _resources(_md_alloc, _label), - _policy(_label) - { - /* non-pci devices */ - _policy.for_each_sub_node("device", [&] (Genode::Xml_node device_node) { + try { + _policy.for_each_sub_node("device", [&] (Xml_node dev) { try { - char policy_device[8]; - device_node.attribute("name").value(policy_device, - sizeof(policy_device)); + /* enforce restriction based on name name */ + char policy_name[8]; + dev.attribute("name").value(policy_name, + sizeof(policy_name)); - enum { DOUBLET = false }; - if (!find_dev_in_policy(policy_device, DOUBLET)) - return; + if (!strcmp(policy_name, name)) + /* found identical match - permit access */ + throw true; - Genode::error("'", _label, "' - device " - "'", Genode::Cstring(policy_device), "' " - "is part of more than one policy"); - } catch (Genode::Xml_node::Nonexistent_attribute) { - Genode::error("'", _label, "' - device node " - "misses a 'name' attribute"); - } - throw Genode::Root::Unavailable(); + } catch (Xml_attribute::Nonexistent_attribute) { } }); + } catch (bool result) { return result; } - /* pci devices */ - _policy.for_each_sub_node("pci", [&] (Genode::Xml_node node) { - enum { INVALID_CLASS = 0x1000000U }; - unsigned class_sub_prog = INVALID_CLASS; + return false; + } - using Genode::Xml_attribute; - - /** - * Valid input is either a triple of 'bus', 'device', - * 'function' attributes or a single 'class' attribute. - * All other attribute names are traded as wrong. - */ - try { - char alias_class[32]; - node.attribute("class").value(alias_class, - sizeof(alias_class)); - - class_sub_prog = class_subclass_prog(alias_class); - if (class_sub_prog >= INVALID_CLASS) { - Genode::error("'", _label, "' - invalid 'class' ", - "attribute '", Genode::Cstring(alias_class), "'"); - throw Genode::Root::Unavailable(); - } - } catch (Xml_attribute::Nonexistent_attribute) { } - - /* if we read a class attribute all is fine */ - if (class_sub_prog < INVALID_CLASS) { - /* sanity check that 'class' is the only attribute */ - try { - node.attribute(1); - Genode::error("'", _label, "' - attributes beside 'class' detected"); - throw Genode::Root::Unavailable(); - } catch (Xml_attribute::Nonexistent_attribute) { } - - /* we have a class and it is the only attribute */ - return; - } - - /* no 'class' attribute - now check for valid bdf triple */ - try { - node.attribute(3); - Genode::error("'", _label, "' - " - "invalid number of pci node attributes"); - throw Genode::Root::Unavailable(); - } catch (Xml_attribute::Nonexistent_attribute) { } + /** + * Check according session policy device usage + */ + bool permit_device(Genode::uint8_t b, Genode::uint8_t d, + Genode::uint8_t f, unsigned class_code) + { + using namespace Genode; + try { + _policy.for_each_sub_node("pci", [&] (Xml_node node) { try { unsigned bus, device, function; @@ -579,334 +445,510 @@ namespace Platform { node.attribute("device").value(&device); node.attribute("function").value(&function); - if ((bus >= Device_config::MAX_BUSES) || - (device >= Device_config::MAX_DEVICES) || - (function >= Device_config::MAX_FUNCTIONS)) - throw Xml_attribute::Nonexistent_attribute(); + if (b == bus && d == device && f == function) + throw true; - enum { DOUBLET = false }; - if (!find_dev_in_policy(bus, device, function, DOUBLET)) - return; + return; + } catch (Xml_attribute::Nonexistent_attribute) { } - Genode::error("'", _label, "' - device '", - Genode::Hex(bus), ":", - Genode::Hex(device), ".", function, "' " - "is part of more than one policy"); + /* enforce restriction based upon classes */ + unsigned class_sub_prog = 0; - } catch (Xml_attribute::Nonexistent_attribute) { - Genode::error("'", _label, "' - " - "invalid pci node attributes for bdf"); - } - throw Genode::Root::Unavailable(); - }); - } - - /** - * Destructor - */ - ~Session_component() - { - /* release all elements of the session's device list */ - while (_device_list.first()) - release_device(_device_list.first()->cap()); - } - - - void upgrade_ram_quota(long quota) { _md_alloc.upgrade(quota); } - - - static void add_config_space(Genode::uint32_t bdf_start, - Genode::uint32_t func_count, - Genode::addr_t base) - { - using namespace Genode; - Config_space * space = - new (env()->heap()) Config_space(bdf_start, func_count, - base); - config_space_list().insert(space); - } - - - /** - * Check whether msi usage was explicitly switched off - */ - bool msi_usage() - { - try { - char mode[8]; - _policy.attribute("irq_mode").value(mode, sizeof(mode)); - if (!Genode::strcmp("nomsi", mode)) - return false; - } catch (Genode::Xml_node::Nonexistent_attribute) { } - - return true; - } - - - /*************************** - ** PCI session interface ** - ***************************/ - - Device_capability first_device(unsigned device_class, - unsigned class_mask) { - return next_device(Device_capability(), device_class, class_mask); } - - Device_capability next_device(Device_capability prev_device, - unsigned device_class, - unsigned class_mask) - { - /* - * Create the interface to the PCI config space. - * This involves the creation of I/O port sessions. - */ - Config_access config_access; - - /* lookup device component for previous device */ - auto lambda = [&] (Device_component *prev) - { - - /* - * Start bus scanning after the previous device's location. - * If no valid device was specified for 'prev_device', - * start at the beginning. - */ - int bus = 0, device = 0, function = -1; - - if (prev) { - Device_config config = prev->config(); - bus = config.bus_number(); - device = config.device_number(); - function = config.function_number(); - } - - /* - * Scan buses for devices. - * If no device is found, return an invalid capability. - */ - Device_config config; - - while (true) { - function += 1; - if (!_find_next(bus, device, function, &config, - &config_access)) - return Device_capability(); - - /* get new bdf values */ - bus = config.bus_number(); - device = config.device_number(); - function = config.function_number(); - - /* if filter of driver don't match skip and continue */ - if ((config.class_code() ^ device_class) & class_mask) - continue; - - /* check that policy permit access to the matched device */ - if (permit_device(bus, device, function, - config.class_code())) - break; - } - - /* lookup if we have a extended pci config space */ - Genode::addr_t config_space = - lookup_config_space(config.bdf()); - - /* - * A device was found. Create a new device component for the - * device and return its capability. - */ try { - Device_component * dev = new (_md_alloc) - Device_component(config, config_space, _ep, this, - &_md_alloc); + char alias_class[32]; + node.attribute("class").value(alias_class, + sizeof(alias_class)); - /* if more than one driver uses the device - warn about */ - if (bdf_in_use.get(Device_config::MAX_BUSES * bus + - Device_config::MAX_DEVICES * device + - function, 1)) - Genode::error("Device ", - Genode::Hex(bus), ":", - Genode::Hex(device), ".", function, " " - "is used by more than one driver - " - "session '", _label, "'."); - else - bdf_in_use.set(Device_config::MAX_BUSES * bus + - Device_config::MAX_DEVICES * device + - function, 1); - - _device_list.insert(dev); - return _ep->manage(dev); - } catch (Genode::Allocator::Out_of_memory) { - throw Out_of_metadata(); + class_sub_prog = class_subclass_prog(alias_class); + } catch (Xml_attribute::Nonexistent_attribute) { + return; } - }; - return _ep->apply(prev_device, lambda); - } - void release_device(Device_capability device_cap) - { - Device_component * device; - auto lambda = [&] (Device_component *d) - { - device = d; - if (!device) + enum { DONT_CHECK_PROGIF = 8 }; + /* if class/subclass don't match - deny */ + if (class_sub_prog && (class_sub_prog ^ class_code) >> DONT_CHECK_PROGIF) return; - unsigned const bus = device->config().bus_number(); - unsigned const dev = device->config().device_number(); - unsigned const func = device->config().function_number(); + /* if this bdf is used by some policy - deny */ + if (find_dev_in_policy(b, d, f)) + return; - if (bdf_in_use.get(Device_config::MAX_BUSES * bus + - Device_config::MAX_DEVICES * dev + - func, 1)) - bdf_in_use.clear(Device_config::MAX_BUSES * bus + - Device_config::MAX_DEVICES * dev + func, 1); + throw true; + }); + } catch (bool result) { return result; } - _device_list.remove(device); - _ep->dissolve(device); - }; + return false; + } - /* lookup device component for previous device */ - _ep->apply(device_cap, lambda); + /** + * Lookup a given device name. + */ + bool find_dev_in_policy(const char * dev_name, bool once = true) + { + using namespace Genode; - if (!device) return; + try { + config()->xml_node().for_each_sub_node("policy", [&] (Xml_node policy) { + policy.for_each_sub_node("device", [&] (Xml_node device) { + try { + /* device attribute from policy node */ + char policy_device[8]; + device.attribute("name").value(policy_device, sizeof(policy_device)); - if (device->config().valid()) - destroy(_md_alloc, device); - else - destroy(_md_alloc, device); - } + if (!strcmp(policy_device, dev_name)) { + if (once) + throw true; + once = true; + } + } catch (Xml_node::Nonexistent_attribute) { } + }); + }); + } catch (bool result) { return result; } - void assign_device(Device_component * device) - { - using namespace Genode; + return false; + } - if (!device || !device->get_config_space().valid()) + /** + * Lookup a given device name. + */ + bool find_dev_in_policy(Genode::uint8_t b, Genode::uint8_t d, + Genode::uint8_t f, bool once = true) + { + using namespace Genode; + + try { + Xml_node xml(config()->xml_node()); + xml.for_each_sub_node("policy", [&] (Xml_node policy) { + policy.for_each_sub_node("pci", [&] (Xml_node node) { + try { + unsigned bus, device, function; + + node.attribute("bus").value(&bus); + node.attribute("device").value(&device); + node.attribute("function").value(&function); + + if (b == bus && d == device && f == function) { + if (once) + throw true; + once = true; + } + } catch (Xml_node::Nonexistent_attribute) { } + }); + }); + } catch (bool result) { return result; } + + return false; + } + + public: + + /** + * Constructor + */ + Session_component(Genode::Rpc_entrypoint &ep, + Genode::Rpc_entrypoint &device_pd_ep, + Genode::Allocator &md_alloc, + char const *args) + : + _ep(ep), _device_pd_ep(device_pd_ep), + _env_ram(*Genode::env()->ram_session()), + _env_ram_cap(Genode::env()->ram_session_cap()), + _local_rm(*(Genode::env()->rm_session())), + _md_alloc(&md_alloc, Genode::Arg_string::find_arg(args, "ram_quota").long_value(0)), + _label(Genode::label_from_args(args)) + { + /* non-pci devices */ + _policy.for_each_sub_node("device", [&] (Genode::Xml_node device_node) { + try { + char policy_device[8]; + device_node.attribute("name").value(policy_device, + sizeof(policy_device)); + + enum { DOUBLET = false }; + if (!find_dev_in_policy(policy_device, DOUBLET)) + return; + + Genode::error("'", _label, "' - device " + "'", Genode::Cstring(policy_device), "' " + "is part of more than one policy"); + } catch (Genode::Xml_node::Nonexistent_attribute) { + Genode::error("'", _label, "' - device node " + "misses a 'name' attribute"); + } + throw Genode::Root::Unavailable(); + }); + + /* pci devices */ + _policy.for_each_sub_node("pci", [&] (Genode::Xml_node node) { + enum { INVALID_CLASS = 0x1000000U }; + unsigned class_sub_prog = INVALID_CLASS; + + using Genode::Xml_attribute; + + /** + * Valid input is either a triple of 'bus', 'device', + * 'function' attributes or a single 'class' attribute. + * All other attribute names are traded as wrong. + */ + try { + char alias_class[32]; + node.attribute("class").value(alias_class, + sizeof(alias_class)); + + class_sub_prog = class_subclass_prog(alias_class); + if (class_sub_prog >= INVALID_CLASS) { + Genode::error("'", _label, "' - invalid 'class' ", + "attribute '", Genode::Cstring(alias_class), "'"); + throw Genode::Root::Unavailable(); + } + } catch (Xml_attribute::Nonexistent_attribute) { } + + /* if we read a class attribute all is fine */ + if (class_sub_prog < INVALID_CLASS) { + /* sanity check that 'class' is the only attribute */ + try { + node.attribute(1); + Genode::error("'", _label, "' - attributes beside 'class' detected"); + throw Genode::Root::Unavailable(); + } catch (Xml_attribute::Nonexistent_attribute) { } + + /* we have a class and it is the only attribute */ return; + } - Io_mem_dataspace_capability io_mem = device->get_config_space(); - - if (!_device_pd.constructed()) - _device_pd.construct(_device_pd_ep, _md_alloc, - _resources.ram().cap(), - _label.string()); - - if (!_device_pd->valid()) - return; + /* no 'class' attribute - now check for valid bdf triple */ + try { + node.attribute(3); + Genode::error("'", _label, "' - " + "invalid number of pci node attributes"); + throw Genode::Root::Unavailable(); + } catch (Xml_attribute::Nonexistent_attribute) { } try { - _device_pd->child.assign_pci(io_mem, device->config().bdf()); + unsigned bus, device, function; - for (Rmrr *r = Rmrr::list()->first(); r; r = r->next()) { - Io_mem_dataspace_capability rmrr_cap = r->match(device->config()); - if (rmrr_cap.valid()) - _device_pd->child.attach_dma_mem(rmrr_cap); - } - } catch (...) { - Genode::error("assignment to device pd or of RMRR region failed"); + node.attribute("bus").value(&bus); + node.attribute("device").value(&device); + node.attribute("function").value(&function); + + if ((bus >= Device_config::MAX_BUSES) || + (device >= Device_config::MAX_DEVICES) || + (function >= Device_config::MAX_FUNCTIONS)) + throw Xml_attribute::Nonexistent_attribute(); + + enum { DOUBLET = false }; + if (!find_dev_in_policy(bus, device, function, DOUBLET)) + return; + + Genode::error("'", _label, "' - device '", + Genode::Hex(bus), ":", + Genode::Hex(device), ".", function, "' " + "is part of more than one policy"); + + } catch (Xml_attribute::Nonexistent_attribute) { + Genode::error("'", _label, "' - " + "invalid pci node attributes for bdf"); } - } + throw Genode::Root::Unavailable(); + }); + } - /** - * De-/Allocation of dma capable dataspaces + /** + * Destructor + */ + ~Session_component() + { + /* release all elements of the session's device list */ + while (_device_list.first()) + release_device(_device_list.first()->cap()); + } + + + void upgrade_ram_quota(long quota) { _md_alloc.upgrade(quota); } + + + static void add_config_space(Genode::uint32_t bdf_start, + Genode::uint32_t func_count, + Genode::addr_t base) + { + using namespace Genode; + Config_space * space = + new (env()->heap()) Config_space(bdf_start, func_count, + base); + config_space_list().insert(space); + } + + + /** + * Check whether msi usage was explicitly switched off + */ + bool msi_usage() + { + try { + char mode[8]; + _policy.attribute("irq_mode").value(mode, sizeof(mode)); + if (!Genode::strcmp("nomsi", mode)) + return false; + } catch (Genode::Xml_node::Nonexistent_attribute) { } + + return true; + } + + + /*************************** + ** PCI session interface ** + ***************************/ + + Device_capability first_device(unsigned device_class, + unsigned class_mask) override { + return next_device(Device_capability(), device_class, class_mask); } + + Device_capability next_device(Device_capability prev_device, + unsigned device_class, + unsigned class_mask) override + { + /* + * Create the interface to the PCI config space. + * This involves the creation of I/O port sessions. */ - typedef Genode::Ram_dataspace_capability Ram_capability; + Config_access config_access; - - /** - * Helper method for rollback - */ - void _rollback(const Genode::size_t size, - const Ram_capability ram_cap = Ram_capability(), - const bool throw_oom = true) + /* lookup device component for previous device */ + auto lambda = [&] (Device_component *prev) { - if (ram_cap.valid()) - _resources.ram().free(ram_cap); - if (_resources.ram().transfer_quota(Genode::env()->ram_session_cap(), size)) - throw Fatal(); + /* + * Start bus scanning after the previous device's location. + * If no valid device was specified for 'prev_device', + * start at the beginning. + */ + int bus = 0, device = 0, function = -1; + if (prev) { + Device_config config = prev->config(); + bus = config.bus_number(); + device = config.device_number(); + function = config.function_number(); + } + + /* + * Scan buses for devices. + * If no device is found, return an invalid capability. + */ + Device_config config; + + while (true) { + function += 1; + if (!_find_next(bus, device, function, &config, + &config_access)) + return Device_capability(); + + /* get new bdf values */ + bus = config.bus_number(); + device = config.device_number(); + function = config.function_number(); + + /* if filter of driver don't match skip and continue */ + if ((config.class_code() ^ device_class) & class_mask) + continue; + + /* check that policy permit access to the matched device */ + if (permit_device(bus, device, function, + config.class_code())) + break; + } + + /* lookup if we have a extended pci config space */ + Genode::addr_t config_space = + lookup_config_space(config.bdf()); + + /* + * A device was found. Create a new device component for the + * device and return its capability. + */ + try { + Device_component * dev = new (_md_alloc) + Device_component(config, config_space, _ep, *this, + _md_alloc); + + /* if more than one driver uses the device - warn about */ + if (bdf_in_use.get(Device_config::MAX_BUSES * bus + + Device_config::MAX_DEVICES * device + + function, 1)) + Genode::error("Device ", + Genode::Hex(bus), ":", + Genode::Hex(device), ".", function, " " + "is used by more than one driver - " + "session '", _label, "'."); + else + bdf_in_use.set(Device_config::MAX_BUSES * bus + + Device_config::MAX_DEVICES * device + + function, 1); + + _device_list.insert(dev); + return _ep.manage(dev); + } catch (Genode::Allocator::Out_of_memory) { + throw Out_of_metadata(); + } + }; + return _ep.apply(prev_device, lambda); + } + + void release_device(Device_capability device_cap) override + { + Device_component * device; + auto lambda = [&] (Device_component *d) + { + device = d; + if (!device) + return; + + unsigned const bus = device->config().bus_number(); + unsigned const dev = device->config().device_number(); + unsigned const func = device->config().function_number(); + + if (bdf_in_use.get(Device_config::MAX_BUSES * bus + + Device_config::MAX_DEVICES * dev + + func, 1)) + bdf_in_use.clear(Device_config::MAX_BUSES * bus + + Device_config::MAX_DEVICES * dev + func, 1); + + _device_list.remove(device); + _ep.dissolve(device); + }; + + /* lookup device component for previous device */ + _ep.apply(device_cap, lambda); + + if (!device) return; + + if (device->config().valid()) + destroy(_md_alloc, device); + else + destroy(_md_alloc, device); + } + + void assign_device(Device_component * device) + { + using namespace Genode; + + if (!device || !device->get_config_space().valid()) + return; + + Io_mem_dataspace_capability io_mem = device->get_config_space(); + + _try_init_device_pd(); + if (!_device_pd) + return; + + try { + _device_pd->session().assign_pci(io_mem, device->config().bdf()); + + for (Rmrr *r = Rmrr::list()->first(); r; r = r->next()) { + Io_mem_dataspace_capability rmrr_cap = r->match(device->config()); + if (rmrr_cap.valid()) + _device_pd->session().attach_dma_mem(rmrr_cap); + } + } catch (...) { + Genode::error("assignment to device pd or of RMRR region failed"); + } + } + + /** + * De-/Allocation of dma capable dataspaces + */ + typedef Genode::Ram_dataspace_capability Ram_capability; + + /** + * Helper method for rollback + */ + void _rollback(Genode::size_t const size, + Genode::Ram_dataspace_capability const ram_cap = Genode::Ram_dataspace_capability(), + bool const throw_oom = true) + { + if (ram_cap.valid()) + _ram.free(ram_cap); + + if (_ram.transfer_quota(_env_ram_cap, size)) + throw Fatal(); + + _md_alloc.upgrade(size); + + if (throw_oom) + throw Out_of_metadata(); + } + + Genode::Ram_dataspace_capability alloc_dma_buffer(Genode::size_t const size) override + { + /* + * We always try to create the device PD first because + * otherwise we might consume the requested size multiple + * times which breaks our accounting. + */ + _try_init_device_pd(); + + if (!_md_alloc.withdraw(size)) + throw Out_of_metadata(); + + /* transfer ram quota to session specific ram session */ + if (_env_ram.transfer_quota(_ram, size)) { _md_alloc.upgrade(size); - - if (throw_oom) - throw Out_of_metadata(); + throw Fatal(); } - Ram_capability alloc_dma_buffer(Genode::size_t const size) - { - if (!_device_pd.constructed()) - _device_pd.construct(_device_pd_ep, _md_alloc, - _resources.ram().cap(), - _label.string()); + enum { UPGRADE_QUOTA = 4096 }; - if (!_md_alloc.withdraw(size)) - throw Out_of_metadata(); + /* allocate dataspace from session specific ram session */ + Ram_capability ram_cap = Genode::retry( + [&] () { + Ram_capability ram = Genode::retry( + [&] () { return _ram.alloc(size, Genode::UNCACHED); }, + [&] () { throw Genode::Ram_session::Quota_exceeded(); }); + return ram; + }, + [&] () { + if (!_md_alloc.withdraw(UPGRADE_QUOTA)) + _rollback(size); - /* transfer ram quota to session specific ram session */ - Genode::Ram_session * const rs = Genode::env()->ram_session(); - if (rs->transfer_quota(_resources.ram().cap(), size)) { - _md_alloc.upgrade(size); - throw Fatal(); - } + _ram.upgrade_ram(UPGRADE_QUOTA); + }); - enum { UPGRADE_QUOTA = 4096 }; + if (!ram_cap.valid()) + return ram_cap; - /* allocate dataspace from session specific ram session */ - Ram_capability ram_cap = Genode::retry( - [&] () { - Ram_capability ram = Genode::retry( - [&] () { return _resources.ram().alloc(size, Genode::UNCACHED); }, - [&] () { throw Genode::Ram_session::Quota_exceeded(); }); - return ram; - }, + if (_device_pd) { + Genode::retry( + [&] () { _device_pd->session().attach_dma_mem(ram_cap); }, [&] () { if (!_md_alloc.withdraw(UPGRADE_QUOTA)) - _rollback(size); + _rollback(size, ram_cap); - char buf[32]; - Genode::snprintf(buf, sizeof(buf), "ram_quota=%u", - UPGRADE_QUOTA); - Genode::env()->parent()->upgrade(_resources.ram().cap(), buf); + if (_env_ram.transfer_quota(_ram, UPGRADE_QUOTA)) + throw Fatal(); + + if (_ram.transfer_quota(_device_pd->ram_session_cap(), UPGRADE_QUOTA)) + throw Fatal(); }); - - if (!ram_cap.valid()) - return ram_cap; - - if (_device_pd->valid()) { - Genode::retry( - [&] () { _device_pd->child.attach_dma_mem(ram_cap); }, - [&] () { - if (!_md_alloc.withdraw(UPGRADE_QUOTA)) - _rollback(size, ram_cap); - - if (rs->transfer_quota(_resources.ram().cap(), UPGRADE_QUOTA)) - throw Fatal(); - - Genode::Ram_connection &slave = _device_pd->policy->ram_slave(); - if (_resources.ram().transfer_quota(slave.cap(), UPGRADE_QUOTA)) - throw Fatal(); - }); - } - - try { - _resources.insert(ram_cap); - } catch(Genode::Allocator::Out_of_memory) { - _rollback(size, ram_cap); - } - return ram_cap; } - void free_dma_buffer(Ram_capability ram_cap) - { - if (!ram_cap.valid() || !_resources.remove(ram_cap)) - return; + try { _insert(ram_cap); } + catch (Genode::Allocator::Out_of_memory) { _rollback(size, ram_cap); } - Genode::size_t size = Genode::Dataspace_client(ram_cap).size(); - _rollback(size, ram_cap, false); - } + return ram_cap; + } + + void free_dma_buffer(Genode::Ram_dataspace_capability ram_cap) override + { + if (!ram_cap.valid() || !_remove(ram_cap)) + return; + + Genode::size_t size = Genode::Dataspace_client(ram_cap).size(); + _rollback(size, ram_cap, false); + } + + Device_capability device(String const &name) override; +}; - Device_capability device(String const &name) override; - }; -} class Platform::Root : public Genode::Root_component { @@ -1072,9 +1114,10 @@ class Platform::Root : public Genode::Root_component Session_component *_create_session(const char *args) { try { - return new (md_alloc()) Session_component(ep(), md_alloc(), - args, _device_pd_ep); - } catch (Genode::Session_policy::No_policy_defined) { + return new (md_alloc()) + Session_component(*ep(), _device_pd_ep, *md_alloc(), args); + } + catch (Genode::Session_policy::No_policy_defined) { Genode::error("Invalid session request, no matching policy for ", "'", Genode::label_from_args(args).string(), "'"); throw Genode::Root::Unavailable(); diff --git a/repos/os/src/drivers/rtc/spec/x86/main.cc b/repos/os/src/drivers/rtc/spec/x86/main.cc index c29df5fc9..c58092421 100644 --- a/repos/os/src/drivers/rtc/spec/x86/main.cc +++ b/repos/os/src/drivers/rtc/spec/x86/main.cc @@ -12,9 +12,8 @@ */ /* Genode */ -#include +#include #include -#include #include #include @@ -52,7 +51,7 @@ class Rtc::Root : public Genode::Root_component public: - Root(Server::Entrypoint &ep, Allocator &md_alloc) + Root(Entrypoint &ep, Allocator &md_alloc) : Genode::Root_component(&ep.rpc_ep(), &md_alloc) { @@ -64,23 +63,14 @@ class Rtc::Root : public Genode::Root_component struct Rtc::Main { - Server::Entrypoint &ep; + Env &env; - Sliced_heap sliced_heap { env()->ram_session(), env()->rm_session() }; + Sliced_heap sliced_heap { env.ram(), env.rm() }; - Root root { ep, sliced_heap }; + Root root { env.ep(), sliced_heap }; - Main(Server::Entrypoint &ep) : ep(ep) - { - env()->parent()->announce(ep.manage(root)); - } + Main(Env &env) : env(env) { env.parent().announce(env.ep().manage(root)); } }; -/********************** - ** Server framework ** - **********************/ - -char const * Server::name() { return "rtc_ep"; } -Genode::size_t Server::stack_size() { return 1024 * sizeof(long); } -void Server::construct(Server::Entrypoint &ep) { static Rtc::Main inst(ep); } +void Component::construct(Genode::Env &env) { static Rtc::Main main(env); } diff --git a/repos/os/src/drivers/rtc/spec/x86/target.mk b/repos/os/src/drivers/rtc/spec/x86/target.mk index 0dffe3c9a..aa42b7bb4 100644 --- a/repos/os/src/drivers/rtc/spec/x86/target.mk +++ b/repos/os/src/drivers/rtc/spec/x86/target.mk @@ -1,7 +1,7 @@ TARGET = rtc_drv REQUIRES = x86 SRC_CC = main.cc -LIBS = base server +LIBS = base # enforce hybrid prg on Linux ifeq ($(filter-out $(SPECS),linux),) diff --git a/repos/os/src/server/loader/README b/repos/os/src/server/loader/README index 3547c3284..d5ea4cac2 100644 --- a/repos/os/src/server/loader/README +++ b/repos/os/src/server/loader/README @@ -3,3 +3,10 @@ subsystems via a session interface. The resources for the new subsystem are provided by the client when opening the session. The client has no control over the functioning of the subsystem except for the controlling the lifetime of the subsystem. + +By default, the loaded subsystem can access only those ROM modules that were +loaded into the loader session by the loader client. However, it is possible +to define a whitelist of ROM modules to be obtained from the loader's parent. +For an example, refer to the example 'run/loader.run' script. + + diff --git a/repos/os/src/server/loader/child.h b/repos/os/src/server/loader/child.h index 42d3ef469..5e1d84247 100644 --- a/repos/os/src/server/loader/child.h +++ b/repos/os/src/server/loader/child.h @@ -29,150 +29,100 @@ namespace Loader { using namespace Genode; + typedef Registered Parent_service; + typedef Registry Parent_services; + class Child : public Child_policy { private: - typedef String Label; + Env &_env; - Label _label; + Session_label const _label; + Name const _binary_name; - Rpc_entrypoint &_ep; + size_t const _ram_quota; - struct Resources - { - Pd_connection pd; - Ram_connection ram; - Cpu_connection cpu; + Parent_services &_parent_services; - Resources(char const *label, - Ram_session_client &ram_session_client, - size_t ram_quota, - Signal_context_capability fault_sigh) - : pd(label), ram(label), cpu(label) - { - /* deduce session costs from usable ram quota */ - size_t session_donations = Cpu_connection::RAM_QUOTA + - Ram_connection::RAM_QUOTA; - - if (ram_quota > session_donations) - ram_quota -= session_donations; - else ram_quota = 0; - - ram.ref_account(ram_session_client); - ram_session_client.transfer_quota(ram.cap(), ram_quota); - - /* - * Install CPU exception and RM fault handler assigned by - * the loader client via 'Loader_session::fault_handler'. - */ - cpu.exception_sigh(fault_sigh); - Region_map_client address_space(pd.address_space()); - address_space.fault_handler(fault_sigh); - } - } _resources; - - Genode::Child::Initial_thread _initial_thread { _resources.cpu, - _resources.pd, - _label.string() }; - - Region_map_client _address_space { _resources.pd.address_space() }; - - Service_registry &_parent_services; Service &_local_nitpicker_service; Service &_local_rom_service; Service &_local_cpu_service; Service &_local_pd_service; - Rom_session_client _binary_rom_session; - - Init::Child_policy_provide_rom_file _binary_policy; Init::Child_policy_enforce_labeling _labeling_policy; Genode::Child _child; - Rom_session_capability _rom_session(char const *name) - { - try { - char args[Session::Name::MAX_SIZE]; - snprintf(args, sizeof(args), "ram_quota=4K, label=\"%s\"", name); - return static_cap_cast(_local_rom_service.session(args, Affinity())); - } catch (Genode::Parent::Service_denied) { - Genode::error("Lookup for ROM module \"", name, "\" failed"); - throw; - } - } - public: - Child(char const *binary_name, - char const *label, - Dataspace_capability ldso_ds, - Rpc_entrypoint &ep, - Ram_session_client &ram_session_client, + Child(Env &env, + Name const &binary_name, + Session_label const &label, size_t ram_quota, - Service_registry &parent_services, + Parent_services &parent_services, Service &local_rom_service, Service &local_cpu_service, Service &local_pd_service, Service &local_nitpicker_service, Signal_context_capability fault_sigh) : + _env(env), _label(label), - _ep(ep), - _resources(_label.string(), ram_session_client, ram_quota, fault_sigh), + _binary_name(binary_name), + _ram_quota(Genode::Child::effective_ram_quota(ram_quota)), _parent_services(parent_services), _local_nitpicker_service(local_nitpicker_service), _local_rom_service(local_rom_service), _local_cpu_service(local_cpu_service), _local_pd_service(local_pd_service), - _binary_rom_session(_rom_session(binary_name)), - _binary_policy("binary", _binary_rom_session.dataspace(), &_ep), _labeling_policy(_label.string()), - _child(_binary_rom_session.dataspace(), ldso_ds, - _resources.pd, _resources.pd, - _resources.ram, _resources.ram, - _resources.cpu, _initial_thread, - *env()->rm_session(), _address_space, _ep, *this) + _child(_env.rm(), _env.ep().rpc_ep(), *this) { } - ~Child() - { - _local_rom_service.close(_binary_rom_session); - } + ~Child() { } /**************************** ** Child-policy interface ** ****************************/ - char const *name() const override { return _label.string(); } + Name name() const override { return _label; } - void filter_session_args(char const *service, char *args, size_t args_len) override + Binary_name binary_name() const override { return _binary_name; } + + Ram_session &ref_ram() override { return _env.ram(); } + Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); } + + void init(Ram_session &ram, Ram_session_capability ram_cap) override { - _labeling_policy.filter_session_args(service, args, args_len); + ram.ref_account(ref_ram_cap()); + ref_ram().transfer_quota(ram_cap, _ram_quota); } - Service *resolve_session_request(const char *name, - const char *args) override + void filter_session_args(Service::Name const &service, char *args, size_t args_len) override { - Service *service = 0; + _labeling_policy.filter_session_args(service.string(), args, args_len); + } - if ((service = _binary_policy.resolve_session_request(name, args))) - return service; - - if (!strcmp(name, "Nitpicker")) return &_local_nitpicker_service; - if (!strcmp(name, "ROM")) return &_local_rom_service; - if (!strcmp(name, "CPU")) return &_local_cpu_service; - if (!strcmp(name, "PD")) return &_local_pd_service; + Service &resolve_session_request(Service::Name const &name, + Session_state::Args const &args) override + { + if (name == "Nitpicker") return _local_nitpicker_service; + if (name == "ROM") return _local_rom_service; + if (name == "CPU") return _local_cpu_service; + if (name == "PD") return _local_pd_service; /* populate session-local parent service registry on demand */ - service = _parent_services.find(name); - if (!service) { - service = new (env()->heap()) Parent_service(name); - _parent_services.insert(service); - } - return service; + Service *service = nullptr; + _parent_services.for_each([&] (Parent_service &s) { + if (s.name() == name) + service = &s; }); + + if (service) + return *service; + + return *new (env()->heap()) Parent_service(_parent_services, name); } }; } diff --git a/repos/os/src/server/loader/main.cc b/repos/os/src/server/loader/main.cc index 8a9329874..283919b43 100644 --- a/repos/os/src/server/loader/main.cc +++ b/repos/os/src/server/loader/main.cc @@ -12,14 +12,13 @@ */ /* Genode includes */ -#include +#include #include #include -#include #include #include -#include #include +#include /* local includes */ #include @@ -41,104 +40,79 @@ class Loader::Session_component : public Rpc_object { private: - struct Local_rom_service : Service + struct Local_rom_factory : Local_service::Factory { - Rpc_entrypoint &_ep; + Entrypoint &_ep; Allocator &_md_alloc; - Parent_service _parent_rom_service; Rom_module_registry &_rom_modules; Lock _lock; List _rom_sessions; - void _close(Rom_session_component *rom) + void _close(Rom_session_component &rom) { - _rom_sessions.remove(rom); - destroy(&_md_alloc, rom); + _rom_sessions.remove(&rom); + Genode::destroy(_md_alloc, &rom); } - Local_rom_service(Rpc_entrypoint &ep, + Local_rom_factory(Entrypoint &ep, Allocator &md_alloc, Rom_module_registry &rom_modules) : - Service("virtual_rom"), - _ep(ep), - _md_alloc(md_alloc), - _parent_rom_service(Rom_session::service_name()), - _rom_modules(rom_modules) + _ep(ep), _md_alloc(md_alloc), _rom_modules(rom_modules) { } - ~Local_rom_service() + ~Local_rom_factory() { Lock::Guard guard(_lock); - while (_rom_sessions.first()) { - _ep.remove(_rom_sessions.first()); - _close(_rom_sessions.first()); - } + while (_rom_sessions.first()) + _close(*_rom_sessions.first()); } - Genode::Session_capability session(char const *args, - Affinity const &affinity) + Rom_session_component &create(Args const &args, Affinity affinity) override { /* try to find ROM module at local ROM service */ try { Lock::Guard guard(_lock); - Session_label const label = label_from_args(args); - Session_label name = label.last_element(); + Session_label const label = label_from_args(args.string()); + Session_label const name = label.last_element(); Rom_module &module = _rom_modules.lookup_and_lock(name.string()); - Rom_session_component *rom = new (&_md_alloc) - Rom_session_component(module); + Rom_session_component *rom = new (_md_alloc) + Rom_session_component(_ep, module); _rom_sessions.insert(rom); - return _ep.manage(rom); + return *rom; } catch (...) { } - /* fall back to parent_rom_service */ - return _parent_rom_service.session(args, affinity); + throw Denied(); } - void close(Session_capability session) + void upgrade(Rom_session_component &, Args const &) override { } + + void destroy(Rom_session_component &session) override { Lock::Guard guard(_lock); - Rom_session_component *component; - - _ep.apply(session, [&] (Rom_session_component *rsc) { - component = rsc; - if (component) _ep.remove(component); - }); - - if (component) { - _close(component); - return; - } - - _parent_rom_service.close(session); + _close(session); } - - void upgrade(Session_capability session, const char *) { } }; + typedef Local_service Local_rom_service; + /** * Common base class of 'Local_cpu_service' and 'Local_pd_service' */ - struct Intercepted_parent_service : Service + struct Intercepted_parent_service : Genode::Parent_service { Signal_context_capability fault_sigh; - Intercepted_parent_service(char const *name) : Service(name) { } - - void close(Session_capability session) - { - env()->parent()->close(session); - } - - void upgrade(Session_capability session, const char *) { } + Intercepted_parent_service(Env &env, Service::Name const &name) + : Parent_service(env, name) { } }; /** @@ -147,20 +121,17 @@ class Loader::Session_component : public Rpc_object */ struct Local_cpu_service : Intercepted_parent_service { - Local_cpu_service() : Intercepted_parent_service("CPU") { } + Local_cpu_service(Env &env) : Intercepted_parent_service(env, "CPU") { } - Genode::Session_capability session(char const *args, - Affinity const &affinity) + void initiate_request(Session_state &session) override { - Capability cap = env()->parent()->session(args, affinity); - Cpu_session_client(cap).exception_sigh(fault_sigh); - return cap; - } + Intercepted_parent_service::initiate_request(session); - void upgrade(Session_capability session, const char *args) - { - try { env()->parent()->upgrade(session, args); } - catch (Genode::Ipc_error) { throw Unavailable(); } + if (session.phase != Session_state::AVAILABLE) + return; + + Cpu_session_client cpu(reinterpret_cap_cast(session.cap)); + cpu.exception_sigh(fault_sigh); } }; @@ -169,109 +140,100 @@ class Loader::Session_component : public Rpc_object */ struct Local_pd_service : Intercepted_parent_service { - Local_pd_service() : Intercepted_parent_service("PD") { } + Local_pd_service(Env &env) : Intercepted_parent_service(env, "PD") { } - Genode::Session_capability session(char const *args, - Affinity const &affinity) + void initiate_request(Session_state &session) override { - Pd_session_client pd(env()->parent()->session(args, affinity)); + Intercepted_parent_service::initiate_request(session); + + if (session.phase != Session_state::AVAILABLE) + return; + + Pd_session_client pd(reinterpret_cap_cast(session.cap)); Region_map_client(pd.address_space()).fault_handler(fault_sigh); Region_map_client(pd.stack_area()) .fault_handler(fault_sigh); Region_map_client(pd.linker_area()) .fault_handler(fault_sigh); - - return pd; } }; - struct Local_nitpicker_service : Service + struct Local_nitpicker_factory : Local_service::Factory { - Rpc_entrypoint &_ep; - Ram_session &_ram; - Allocator &_md_alloc; + Entrypoint &_ep; + Ram_session &_ram; Area _max_size; Nitpicker::View_capability _parent_view; Signal_context_capability view_ready_sigh; - Nitpicker::Session_component *open_session; + Lazy_volatile_object session; - Local_nitpicker_service(Rpc_entrypoint &ep, Ram_session &ram, - Allocator &md_alloc) - : - Service("virtual_nitpicker"), - _ep(ep), - _ram(ram), - _md_alloc(md_alloc), - open_session(0) - { } + Local_nitpicker_factory(Entrypoint &ep, Ram_session &ram) + : _ep(ep), _ram(ram) { } - ~Local_nitpicker_service() - { - if (!open_session) - return; - - _ep.dissolve(open_session); - destroy(&_md_alloc, open_session); - } - - void constrain_geometry(Area size) - { - _max_size = size; - } + void constrain_geometry(Area size) { _max_size = size; } void parent_view(Nitpicker::View_capability view) { _parent_view = view; } - Genode::Session_capability session(char const *args, - Affinity const &) + Nitpicker::Session_component &create(Args const &args, Affinity) override { - if (open_session) - throw Unavailable(); + if (session.constructed()) { + warning("attempt to open more than one nitpicker session"); + throw Parent::Service_denied(); + } - open_session = new (&_md_alloc) - Nitpicker::Session_component(_ep, - _ram, - _max_size, - _parent_view, - view_ready_sigh, - args); - - return _ep.manage(open_session); + session.construct(_ep, _ram, _max_size, + _parent_view, view_ready_sigh, args.string()); + return *session; } - void upgrade(Genode::Session_capability session, const char *) { } + void upgrade(Nitpicker::Session_component &, Args const &) override { } + void destroy(Nitpicker::Session_component &) override { } }; + typedef Local_service Local_nitpicker_service; + enum { STACK_SIZE = 2*4096 }; - size_t _ram_quota; - Ram_session_client_guard _ram_session_client; - Heap _md_alloc; - size_t _subsystem_ram_quota_limit; - Rpc_entrypoint _ep; - Dataspace_capability _ldso_ds; - Service_registry _parent_services; - Rom_module_registry _rom_modules; - Local_rom_service _rom_service; - Local_cpu_service _cpu_service; - Local_pd_service _pd_service; - Local_nitpicker_service _nitpicker_service; - Signal_context_capability _fault_sigh; - Child *_child; + Env &_env; + Session_label const _label; + Xml_node const _config; + size_t const _ram_quota; + Ram_session_client_guard _local_ram { _env.ram_session_cap(), _ram_quota }; + Heap _md_alloc { _local_ram, _env.rm() }; + size_t _subsystem_ram_quota_limit = 0; + Parent_services _parent_services; + Rom_module_registry _rom_modules { _env, _config, _local_ram, _md_alloc }; + Local_rom_factory _rom_factory { _env.ep(), _md_alloc, _rom_modules }; + Local_rom_service _rom_service { _rom_factory }; + Local_cpu_service _cpu_service { _env }; + Local_pd_service _pd_service { _env }; + Local_nitpicker_factory _nitpicker_factory { _env.ep(), _local_ram }; + Local_nitpicker_service _nitpicker_service { _nitpicker_factory }; + Signal_context_capability _fault_sigh; + Lazy_volatile_object _child; /** * Return virtual nitpicker session component */ - Nitpicker::Session_component &_virtual_nitpicker_session() const + Nitpicker::Session_component &_virtual_nitpicker_session() { - if (!_nitpicker_service.open_session) + if (!_nitpicker_factory.session.constructed()) throw View_does_not_exist(); - return *_nitpicker_service.open_session; + return *_nitpicker_factory.session; + } + + Nitpicker::Session_component const &_virtual_nitpicker_session() const + { + if (!_nitpicker_factory.session.constructed()) + throw View_does_not_exist(); + + return *_nitpicker_factory.session; } public: @@ -279,34 +241,30 @@ class Loader::Session_component : public Rpc_object /** * Constructor */ - Session_component(size_t quota, Ram_session &ram, Cap_session &cap, - Dataspace_capability ldso_ds) + Session_component(Env &env, Session_label const &label, + Xml_node config, size_t quota) : - _ram_quota(quota), - _ram_session_client(env()->ram_session_cap(), _ram_quota), - _md_alloc(&_ram_session_client, env()->rm_session()), - _subsystem_ram_quota_limit(0), - _ep(&cap, STACK_SIZE, "session_ep"), - _ldso_ds(ldso_ds), - _rom_modules(_ram_session_client, _md_alloc), - _rom_service(_ep, _md_alloc, _rom_modules), - _nitpicker_service(_ep, _ram_session_client, _md_alloc), - _child(0) - { } + _env(env), _label(label), _config(config), _ram_quota(quota) + { + /* fetch all parent-provided ROMs according to the config */ + config.for_each_sub_node("parent-rom", [&] (Xml_node rom) + { + typedef Rom_module::Name Name; + Name name = rom.attribute_value("name", Name()); + _rom_modules.fetch_parent_rom_module(name); + }); + } ~Session_component() { - if (_child) - destroy(&_md_alloc, _child); + _child.destruct(); /* * The parent-service registry is populated by the 'Child' * on demand. Revert those allocations. */ - while (Service *service = _parent_services.find_by_server(0)) { - _parent_services.remove(service); - destroy(env()->heap(), service); - } + _parent_services.for_each([&] (Parent_service &service) { + destroy(env()->heap(), &service); }); } @@ -334,17 +292,17 @@ class Loader::Session_component : public Rpc_object void constrain_geometry(Area size) override { - _nitpicker_service.constrain_geometry(size); + _nitpicker_factory.constrain_geometry(size); } void parent_view(Nitpicker::View_capability view) override { - _nitpicker_service.parent_view(view); + _nitpicker_factory.parent_view(view); } void view_ready_sigh(Signal_context_capability sigh) override { - _nitpicker_service.view_ready_sigh = sigh; + _nitpicker_factory.view_ready_sigh = sigh; } void fault_sigh(Signal_context_capability sigh) override @@ -369,22 +327,21 @@ class Loader::Session_component : public Rpc_object void start(Name const &binary_name, Name const &label) override { - if (_child) { - PWRN("cannot start subsystem twice"); + if (_child.constructed()) { + warning("cannot start subsystem twice"); return; } - size_t const ram_quota = (_subsystem_ram_quota_limit > 0) ? - min(_subsystem_ram_quota_limit, _ram_session_client.avail()) : - _ram_session_client.avail(); + size_t const ram_quota = (_subsystem_ram_quota_limit > 0) + ? min(_subsystem_ram_quota_limit, _ram_quota) + : _ram_quota; try { - _child = new (&_md_alloc) - Child(binary_name.string(), label.string(), _ldso_ds, - _ep, _ram_session_client, - ram_quota, _parent_services, _rom_service, - _cpu_service, _pd_service, _nitpicker_service, - _fault_sigh); + _child.construct(_env, binary_name.string(), + prefixed_label(_label, Session_label(label.string())), + ram_quota, _parent_services, _rom_service, + _cpu_service, _pd_service, _nitpicker_service, + _fault_sigh); } catch (Genode::Parent::Service_denied) { throw Rom_module_does_not_exist(); } @@ -406,61 +363,53 @@ class Loader::Root : public Root_component { private: - Ram_session &_ram; - Cap_session &_cap; - Dataspace_capability _ldso_ds; + Env &_env; + Xml_node const _config; protected: Session_component *_create_session(const char *args) { - size_t quota = - Arg_string::find_arg(args, "ram_quota").ulong_value(0); + size_t quota = Arg_string::find_arg(args, "ram_quota").ulong_value(0); - return new (md_alloc()) Session_component(quota, _ram, _cap, _ldso_ds); + Xml_node session_config(""); + + Session_label const label = label_from_args(args); + + try { session_config = Session_policy(label, _config); } + catch (...) { } + + return new (md_alloc()) Session_component(_env, label, session_config, quota); } public: - /** - * Constructor - * - * \param session_ep entry point for managing ram session objects - * \param md_alloc meta-data allocator to be used by root - * component - */ - Root(Rpc_entrypoint &session_ep, Allocator &md_alloc, - Ram_session &ram, Cap_session &cap, Dataspace_capability ldso_ds) + Root(Env &env, Xml_node config, Allocator &md_alloc) : - Root_component(&session_ep, &md_alloc), - _ram(ram), _cap(cap), _ldso_ds(ldso_ds) + Root_component(&env.ep().rpc_ep(), &md_alloc), + _env(env), _config(config) { } }; -Genode::Dataspace_capability request_ldso_ds() +namespace Loader { struct Main; } + + +struct Loader::Main { - try { - static Genode::Rom_connection rom("ld.lib.so"); - return rom.dataspace(); - } catch (...) { } - return Genode::Dataspace_capability(); -} + Env &env; + + Heap heap { env.ram(), env.rm() }; + + Attached_rom_dataspace config { env, "config" }; + + Root root { env, config.xml(), heap }; + + Main(Env &env) : env(env) + { + env.parent().announce(env.ep().manage(root)); + } +}; -int main() -{ - using namespace Genode; - - enum { STACK_SIZE = 8*1024 }; - static Cap_connection cap; - static Rpc_entrypoint ep(&cap, STACK_SIZE, "loader_ep"); - - static Loader::Root root(ep, *env()->heap(), *env()->ram_session(), cap, - request_ldso_ds()); - - env()->parent()->announce(ep.manage(&root)); - - sleep_forever(); - return 0; -} +void Component::construct(Genode::Env &env) { static Loader::Main main(env); } diff --git a/repos/os/src/server/loader/nitpicker.h b/repos/os/src/server/loader/nitpicker.h index 80ac11d87..b7505f622 100644 --- a/repos/os/src/server/loader/nitpicker.h +++ b/repos/os/src/server/loader/nitpicker.h @@ -39,7 +39,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object */ Genode::Signal_context_capability _view_ready_sigh; - Genode::Rpc_entrypoint &_ep; + Genode::Entrypoint &_ep; Area _max_size; @@ -148,7 +148,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object /** * Constructor */ - Session_component(Genode::Rpc_entrypoint &ep, + Session_component(Genode::Entrypoint &ep, Genode::Ram_session &ram, Area max_size, Nitpicker::View_capability parent_view, @@ -166,10 +166,18 @@ class Nitpicker::Session_component : public Genode::Rpc_object _view_handle(_nitpicker.create_view(_parent_view_handle)), _proxy_input(_nitpicker.input_session(), _motion_delta), - _proxy_input_cap(_ep.manage(&_proxy_input)), + _proxy_input_cap(_ep.manage(_proxy_input)), _command_ds(&ram, sizeof(Command_buffer)) - { } + { + _ep.manage(*this); + } + + ~Session_component() + { + _ep.dissolve(_proxy_input); + _ep.dissolve(*this); + } /********************************* diff --git a/repos/os/src/server/loader/rom.h b/repos/os/src/server/loader/rom.h index b6cdde8e2..78a834830 100644 --- a/repos/os/src/server/loader/rom.h +++ b/repos/os/src/server/loader/rom.h @@ -11,20 +11,26 @@ #include #include #include +#include namespace Genode { class Rom_module : public List::Element { + public: + + typedef String<128> Name; + private: - enum { MAX_NAME_LEN = 64 }; - char _name[MAX_NAME_LEN]; + Name const _name; Ram_session &_ram; Attached_ram_dataspace _fg; Attached_ram_dataspace _bg; + Lazy_volatile_object _parent_rom; + bool _bg_has_pending_data; Signal_context_capability _sigh; @@ -33,20 +39,28 @@ namespace Genode { public: - Rom_module(char const *name, Ram_session &ram_session) + enum Origin { PARENT_PROVIDED, SESSION_LOCAL }; + + Rom_module(Env &env, Xml_node config, Name const &name, + Ram_session &ram_session, Origin origin) : - _ram(ram_session), + _name(name), _ram(ram_session), _fg(&_ram, 0), _bg(&_ram, 0), _bg_has_pending_data(false), _lock(Lock::LOCKED) { - strncpy(_name, name, sizeof(_name)); + if (origin == SESSION_LOCAL) + return; + + try { + _parent_rom.construct(env, name.string()); } + catch (...) { + warning("ROM ", name, " unavailable from parent, " + "try to use session-local ROM"); + } } - bool has_name(char const *name) const - { - return strcmp(_name, name) == 0; - } + bool has_name(Name const &name) const { return _name == name; } void lock() { _lock.lock(); } void unlock() { _lock.unlock(); } @@ -72,6 +86,9 @@ namespace Genode { */ Rom_dataspace_capability fg_dataspace() { + if (_parent_rom.constructed()) + return static_cap_cast(_parent_rom->cap()); + if (!_fg.size() && !_bg_has_pending_data) { Genode::error("no data loaded"); return Rom_dataspace_capability(); @@ -95,7 +112,13 @@ namespace Genode { * * This function is indirectly called by the ROM session client. */ - void sigh(Signal_context_capability sigh) { _sigh = sigh; } + void sigh(Signal_context_capability sigh) + { + if (_parent_rom.constructed()) + _parent_rom->sigh(sigh); + + _sigh = sigh; + } /** * Commit data contained in background dataspace @@ -126,6 +149,8 @@ namespace Genode { { private: + Env &_env; + Xml_node const _config; Lock _lock; Ram_session &_ram_session; Allocator &_md_alloc; @@ -145,9 +170,11 @@ namespace Genode { * module data * \param md_alloc backing store for ROM module meta data */ - Rom_module_registry(Ram_session &ram_session, Allocator &md_alloc) + Rom_module_registry(Env &env, Xml_node config, Ram_session &ram_session, + Allocator &md_alloc) : - _ram_session(ram_session), _md_alloc(md_alloc) + _env(env), _config(config), _ram_session(ram_session), + _md_alloc(md_alloc) { } ~Rom_module_registry() @@ -167,7 +194,7 @@ namespace Genode { * * \throw Lookup_failed */ - Rom_module &lookup_and_lock(char const *name) + Rom_module &lookup_and_lock(Rom_module::Name const &name) { Lock::Guard guard(_lock); @@ -181,7 +208,7 @@ namespace Genode { throw Lookup_failed(); } - Dataspace_capability alloc_rom_module(char const *name, size_t size) + Dataspace_capability alloc_rom_module(Rom_module::Name const &name, size_t size) { try { Rom_module &module = lookup_and_lock(name); @@ -193,7 +220,8 @@ namespace Genode { Lock::Guard guard(_lock); Rom_module *module = new (&_md_alloc) - Rom_module(name, _ram_session); + Rom_module(_env, _config, name, _ram_session, + Rom_module::SESSION_LOCAL); Rom_module_lock_guard module_guard(*module); @@ -203,6 +231,25 @@ namespace Genode { } } + void fetch_parent_rom_module(Rom_module::Name const &name) + { + try { + lookup_and_lock(name); + } + catch (Lookup_failed) { + + Lock::Guard guard(_lock); + + Rom_module *module = new (&_md_alloc) + Rom_module(_env, _config, name, _ram_session, + Rom_module::PARENT_PROVIDED); + + Rom_module_lock_guard module_guard(*module); + + _list.insert(module); + } + } + /** * \throw Lookup_failed */ @@ -220,12 +267,15 @@ namespace Genode { { private: + Entrypoint &_ep; Rom_module &_rom_module; public: - Rom_session_component(Rom_module &rom_module) - : _rom_module(rom_module) { } + Rom_session_component(Entrypoint &ep, Rom_module &rom_module) + : _ep(ep), _rom_module(rom_module) { _ep.manage(*this); } + + ~Rom_session_component() { _ep.dissolve(*this); } Rom_dataspace_capability dataspace() { diff --git a/repos/os/src/server/mixer/mixer.cc b/repos/os/src/server/mixer/mixer.cc index 328f7329e..c0bc2d6f1 100644 --- a/repos/os/src/server/mixer/mixer.cc +++ b/repos/os/src/server/mixer/mixer.cc @@ -691,7 +691,7 @@ class Audio_out::Root : public Audio_out::Root_component void _destroy_session(Session_component *session) { if (--_sessions == 0) _mixer.stop(); - destroy(md_alloc(), session); + Genode::destroy(md_alloc(), session); } public: diff --git a/repos/os/src/server/nitpicker/main.cc b/repos/os/src/server/nitpicker/main.cc index 7658ec573..dcf34c4e9 100644 --- a/repos/os/src/server/nitpicker/main.cc +++ b/repos/os/src/server/nitpicker/main.cc @@ -1072,7 +1072,7 @@ class Nitpicker::Root : public Genode::Root_component session->destroy_all_views(); _mode.forget(*session); - destroy(md_alloc(), session); + Genode::destroy(md_alloc(), session); } public: diff --git a/repos/os/src/test/bomb/main.cc b/repos/os/src/test/bomb/main.cc index cf81a39da..1cf57139c 100644 --- a/repos/os/src/test/bomb/main.cc +++ b/repos/os/src/test/bomb/main.cc @@ -1,6 +1,7 @@ /* * \brief Fork bomb to stress Genode * \author Christian Helmuth + * \author Norman Feske * \date 2007-08-16 * * The better part of this code is derived from the original init @@ -8,165 +9,128 @@ */ /* - * Copyright (C) 2007-2013 Genode Labs GmbH + * Copyright (C) 2007-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ -#include +#include #include #include #include -#include +#include #include -#include -#include -#include -#include -#include #include - -#include #include -#include using namespace Genode; -class Bomb_child_resources -{ - protected: - - Genode::Session_label _rom_label; - - Genode::Pd_connection _pd; - Genode::Rom_connection _rom; - Genode::Ram_connection _ram; - Genode::Cpu_connection _cpu; - - typedef String<32> Name; - Name _name; - - Genode::Region_map_client _address_space { _pd.address_space() }; - - Bomb_child_resources(const char *elf_name, const char *name, - Genode::size_t ram_quota) - : - _rom_label(Genode::prefixed_label(Genode::Session_label(name), - Genode::Session_label(elf_name))), - _pd(name), _rom(_rom_label.string()), - _ram(name), _cpu(name), _name(name) - { - _ram.ref_account(env()->ram_session_cap()); - Genode::env()->ram_session()->transfer_quota(_ram.cap(), ram_quota); - - if (!_ram.cap().valid() || !_cpu.cap().valid()) { - class Ram_or_cpu_session_not_valid { }; - throw Ram_or_cpu_session_not_valid(); - } - } -}; - - -class Bomb_child : private Bomb_child_resources, - public Genode::Child_policy, - public Genode::List::Element +class Bomb_child : public Child_policy { private: - Init::Child_policy_enforce_labeling _enforce_labeling_policy; - - Genode::Child::Initial_thread _initial_thread; + Env &_env; + Binary_name const _binary_name; + Name const _label; + size_t const _ram_quota; /* * Entry point used for serving the parent interface */ - enum { STACK_SIZE = 2048 * sizeof(Genode::addr_t) }; - Genode::Rpc_entrypoint _entrypoint; + enum { STACK_SIZE = 2048 * sizeof(addr_t) }; + Rpc_entrypoint _ep { &_env.pd(), STACK_SIZE, "bomb_ep_child", false }; - Genode::Child _child; - Genode::Service_registry *_parent_services; - Genode::Child_policy_dynamic_rom_file _config_policy; + Registry > &_parent_services; + + Init::Child_policy_enforce_labeling _labeling_policy { _label.string() }; + Child_policy_dynamic_rom_file _config_policy { "config", _ep, &_env.ram() }; + + Child _child { _env.rm(), _ep, *this }; public: - Bomb_child(const char *file_name, - const char *unique_name, - Genode::size_t ram_quota, - Cap_session *cap_session, - Service_registry *parent_services, - unsigned generation) + Bomb_child(Env &env, + Name const &binary_name, + Name const &label, + size_t ram_quota, + Registry > &parent_services, + unsigned generation) : - Bomb_child_resources(file_name, unique_name, ram_quota), - _enforce_labeling_policy(_name.string()), - _initial_thread(_cpu, _pd, unique_name), - _entrypoint(cap_session, STACK_SIZE, "bomb_ep_child", false), - _child(_rom.dataspace(), Genode::Dataspace_capability(), - _pd, _pd, _ram, _ram, _cpu, _initial_thread, - *Genode::env()->rm_session(), _address_space, _entrypoint, *this), - _parent_services(parent_services), - _config_policy("config", _entrypoint, &_ram) + _env(env), _binary_name(binary_name), _label(label), + _ram_quota(Child::effective_ram_quota(ram_quota)), + _parent_services(parent_services) { - char client_config[64]; - snprintf(client_config, sizeof(client_config), - "", generation); - _config_policy.load(client_config, strlen(client_config) + 1); - - _entrypoint.activate(); + String<64> config(""); + _config_policy.load(config.string(), config.length()); + _ep.activate(); } - ~Bomb_child() { Genode::log(__PRETTY_FUNCTION__); } + ~Bomb_child() { log(__PRETTY_FUNCTION__); } /**************************** ** Child-policy interface ** ****************************/ - const char *name() const { return Bomb_child_resources::_name.string(); } + Name name() const override { return _label; } - void filter_session_args(const char * x, char *args, Genode::size_t args_len) + Binary_name binary_name() const override { return _binary_name; } + + void init(Ram_session &ram, Ram_session_capability ram_cap) override { - _enforce_labeling_policy.filter_session_args(0, args, args_len); + ram.ref_account(_env.ram_session_cap()); + _env.ram().transfer_quota(ram_cap, _ram_quota); } - Service *resolve_session_request(const char *service_name, - const char *args) + Ram_session &ref_ram() override { return _env.ram(); } + Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); } + + void filter_session_args(Service::Name const &, + char *args, size_t args_len) override { - Service * service = nullptr; + _labeling_policy.filter_session_args(nullptr, args, args_len); + } + + Service &resolve_session_request(Service::Name const &service_name, + Session_state::Args const &args) override + { + Service *service = nullptr; /* check for config file request */ - if ((service = _config_policy.resolve_session_request(service_name, - args))) - return service; + if ((service = _config_policy.resolve_session_request(service_name.string(), + args.string()))) + return *service; - return _parent_services->find(service_name); + _parent_services.for_each([&] (Service &s) { + if (!service && service_name == s.name()) + service = &s; }); + + if (!service) + throw Parent::Service_denied(); + + return *service; } }; -/* - * List of children - * - * Access to the children list from different threads - * must be synchronized via the children lock. - */ -static Lock _children_lock; -static List _children; +typedef Registry > Children; /** * Check if a program with the specified name already exists */ -static bool child_name_exists(const char *name) +static bool child_name_exists(Children const &children, + Bomb_child::Name const &name) { - Bomb_child *c = _children.first(); + bool found = false; - for ( ; c; c = c->List::Element::next()) - if (strcmp(c->name(), name) == 0) - return true; + children.for_each([&] (Bomb_child const &child) { + if (!found && child.name() == name) + found = true; }); - return false; + return found; } @@ -176,80 +140,28 @@ static bool child_name_exists(const char *name) * If a program with the filename as name already exists, we * add a counting number as suffix. */ -static void get_unique_child_name(const char *filename, char *dst, - size_t dst_len, unsigned generation) +static Bomb_child::Name +unique_child_name(Children const &children, Bomb_child::Name const &binary_name, + unsigned const generation) { - Lock::Guard lock_guard(_children_lock); + /* serialize calls to this function */ + static Lock lock; + Lock::Guard guard(lock); - char buf[32]; - char suffix[8]; - suffix[0] = 0; - - for (int cnt = 1; true; cnt++) { - - /* build program name composed of filename and numeric suffix */ - snprintf(buf, sizeof(buf), "%s_g%u%s", filename, generation, suffix); + for (unsigned cnt = 1; ; cnt++) { /* if such a program name does not exist yet, we are happy */ - if (!child_name_exists(buf)) { - strncpy(dst, buf, dst_len); - return; - } - - /* increase number of suffix */ - snprintf(suffix, sizeof(suffix), ".%d", cnt + 1); + Bomb_child::Name const unique(binary_name, "_g", generation, ".", cnt); + if (!child_name_exists(children, unique.string())) + return unique; } } -/** - * Start a child - */ -static int start_child(const char *file_name, Cap_session *cap_session, - size_t ram_quota, Service_registry *parent_services, - unsigned generation) +void Component::construct(Genode::Env &env) { - char name[64]; - get_unique_child_name(file_name, name, sizeof(name), generation); - - Bomb_child *c = new (env()->heap()) - Bomb_child(file_name, name, ram_quota, cap_session, parent_services, - generation); - - Lock::Guard lock_guard(_children_lock); - _children.insert(c); - return 0; -} - - -/** - * Kill child - */ -static void exit_child(Bomb_child *child) -{ - destroy(env()->heap(), child); -} - - -/** - * Request timer service - * - * \return timer session, or 0 if bomb is our parent - */ -Timer::Session *timer() -{ - try { - static Timer::Connection timer_inst; - return &timer_inst; - } catch (Parent::Service_denied) { } - - return 0; -} - - -int main(int argc, char **argv) -{ - Genode::Xml_node node = config()->xml_node(); + static Attached_rom_dataspace config(env, "config"); + Xml_node node = config.xml(); unsigned const rounds = node.attribute_value("rounds", 1U); unsigned const generation = node.attribute_value("generations", 1U); @@ -258,23 +170,26 @@ int main(int argc, char **argv) unsigned long const demand = node.attribute_value("demand", 1024UL * 1024); log("--- bomb started ---"); - if (timer()) + + /* try to create timer session, if it fails, bomb is our parent */ + static Lazy_volatile_object timer; + try { timer.construct(env); } catch (Parent::Service_denied) { } + + if (timer.constructed()) log("rounds=", rounds, " generations=", generation, " children=", children, " sleep=", sleeptime, " demand=", demand/1024, "K"); - - /* connect to core's cap service used for creating parent capabilities */ - Cap_connection cap; - /* names of services provided by the parent */ static const char *names[] = { - "CAP", "RAM", "RM", "PD", "CPU", "ROM", "LOG", 0 }; + "RAM", "PD", "CPU", "ROM", "LOG", 0 }; - static Service_registry parent_services; + static Heap heap(env.ram(), env.rm()); + + static Registry > parent_services; for (unsigned i = 0; names[i]; i++) - parent_services.insert(new (env()->heap()) Parent_service(names[i])); + new (heap) Registered(parent_services, names[i]); - unsigned long avail = env()->ram_session()->avail(); + unsigned long avail = env.ram().avail(); unsigned long amount = (avail - demand) / children; if (amount < (demand * children)) { log("I'm a leaf node - generation ", generation, " - not enough memory."); @@ -285,43 +200,42 @@ int main(int argc, char **argv) sleep_forever(); } + static Children child_registry; + + Bomb_child::Name const binary_name("bomb"); + for (unsigned round = 0; round < rounds ; ++round) { - for (unsigned i = children; i; --i) - start_child("bomb", &cap, amount, &parent_services, generation - 1); + for (unsigned i = children; i; --i) { + new (heap) + Registered(child_registry, env, binary_name, + unique_child_name(child_registry, binary_name, + generation - 1), + amount, parent_services, generation - 1); + } /* is init our parent? */ - if (!timer()) sleep_forever(); + if (!timer.constructed()) sleep_forever(); /* don't ask parent for further resources if we ran out of memory */ static Signal_receiver sig_rec; static Signal_context sig_ctx_res_avail; if (round == 0) { /* prevent to block for resource upgrades caused by clients */ - env()->parent()->resource_avail_sigh(sig_rec.manage(&sig_ctx_res_avail)); + env.parent().resource_avail_sigh(sig_rec.manage(&sig_ctx_res_avail)); } - timer()->msleep(sleeptime); + timer->msleep(sleeptime); log("[", round, "] It's time to kill all my children..."); - while (1) { - Bomb_child *c; - - _children_lock.lock(); - c = _children.first(); - if (c) _children.remove(c); - _children_lock.unlock(); - - if (c) exit_child(c); - else break; - } + child_registry.for_each([&] (Registered &child) { + destroy(heap, &child); }); log("[", round, "] Done."); } /* master if we have a timer connection */ - if (timer()) + if (timer.constructed()) log("Done. Going to sleep"); sleep_forever(); - return 0; } diff --git a/repos/os/src/test/dynamic_config/master/main.cc b/repos/os/src/test/dynamic_config/master/main.cc index f7a532a3a..1cd08dc36 100644 --- a/repos/os/src/test/dynamic_config/master/main.cc +++ b/repos/os/src/test/dynamic_config/master/main.cc @@ -5,63 +5,78 @@ */ /* - * Copyright (C) 2012-2013 Genode Labs GmbH + * Copyright (C) 2012-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ /* Genode includes */ +#include #include #include -#include -struct Test_slave_policy : Genode::Slave_policy +namespace Test { + + using namespace Genode; + + struct Policy; + struct Main; +} + + +struct Test::Policy : Genode::Slave::Policy { const char **_permitted_services() const { static const char *permitted_services[] = { - "RM", "LOG", 0 }; + "CPU", "RAM", "ROM", "PD", "LOG", 0 }; return permitted_services; }; - Test_slave_policy(char const *name, Genode::Rpc_entrypoint &ep) - : Genode::Slave_policy(name, ep, Genode::env()->ram_session()) + Policy(Genode::Env &env, Name const &name) + : + Genode::Slave::Policy(name, name, env.ep().rpc_ep(), env.rm(), + env.ram_session_cap(), 1024*1024) { } }; -int main(int, char **) +struct Test::Main { - using namespace Genode; + Env &_env; - enum { STACK_SIZE = 2*4096 }; - static Cap_connection cap; - static Rpc_entrypoint ep(&cap, STACK_SIZE, "slave_ep"); + Policy _policy { _env, "test-dynamic_config" }; - static Test_slave_policy slave_policy("test-dynamic_config", ep); + unsigned _cnt = 0; - /* define initial config for slave */ - slave_policy.configure("-1"); - - static Genode::Slave slave(ep, slave_policy, 768*1024); - - /* update slave config at regular intervals */ - int counter = 0; - for (;;) { - - static Timer::Connection timer; - timer.msleep(250); - - /* re-generate configuration */ - char buf[100]; - Genode::snprintf(buf, sizeof(buf), - "%d", - counter++); - - slave_policy.configure(buf); + void _configure() + { + String<256> const config("", _cnt, ""); + _policy.configure(config.string()); + _cnt++; } - return 0; -} + + Child _child { _env.rm(), _env.ep().rpc_ep(), _policy }; + + Timer::Connection timer { _env }; + + Signal_handler
_timeout_handler { _env.ep(), *this, &Main::_handle_timeout }; + + void _handle_timeout() { _configure(); } + + Main(Env &env) : _env(env) + { + /* update slave config at regular intervals */ + timer.sigh(_timeout_handler); + timer.trigger_periodic(250*1000); + + /* define initial config for slave before returning to entrypoint */ + _configure(); + } +}; + + +void Component::construct(Genode::Env &env) { static Test::Main main(env); } diff --git a/repos/os/src/test/fault_detection/main.cc b/repos/os/src/test/fault_detection/main.cc index 48f28efdb..8b8725814 100644 --- a/repos/os/src/test/fault_detection/main.cc +++ b/repos/os/src/test/fault_detection/main.cc @@ -5,110 +5,91 @@ */ /* - * Copyright (C) 2008-2013 Genode Labs GmbH + * Copyright (C) 2008-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ #include -#include -#include +#include #include -#include #include -#include -#include -#include +#include #include #include +using namespace Genode; -/*************** - ** Utilities ** - ***************/ -static void wait_for_signal_for_context(Genode::Signal_receiver &sig_rec, - Genode::Signal_context const &sig_ctx) +template +class Iterative_test { - Genode::Signal s = sig_rec.wait_for_signal(); + public: - if (s.num() && s.context() == &sig_ctx) { - Genode::log("got exception for child"); - } else { - Genode::error("got unexpected signal while waiting for child"); - class Unexpected_signal { }; - throw Unexpected_signal(); - } -} + private: + + Env &_env; + Signal_context_capability _finished_sigh; + unsigned const _cnt_max = 5; + unsigned _cnt = 0; + + Signal_handler _fault_handler { + _env.ep(), *this, &Iterative_test::_handle_fault }; + + TEST _test;; + + void _handle_fault() + { + if (_cnt++ >= _cnt_max) { + Signal_transmitter(_finished_sigh).submit(); + log("-- finished ", _test.name(), " --"); + return; + } + _test.start_iteration(_env, _fault_handler); + } + + public: + + Iterative_test(Env &env, Signal_context_capability finished_sigh) + : + _env(env), _finished_sigh(finished_sigh) + { + log("-- exercise ", _test.name(), " --"); + _test.start_iteration(_env, _fault_handler); + } +}; -/****************************************************************** - ** Test for detecting the failure of an immediate child process ** - ******************************************************************/ +/******************************************************************** + ** Test for detecting the failure of an immediate child component ** + ********************************************************************/ class Test_child : public Genode::Child_policy { private: - struct Resources - { - Genode::Pd_connection pd; - Genode::Ram_connection ram; - Genode::Cpu_connection cpu; - - Resources(Genode::Signal_context_capability sigh, char const *label) - : pd(label) - { - using namespace Genode; - - /* transfer some of our own ram quota to the new child */ - enum { CHILD_QUOTA = 1*1024*1024 }; - ram.ref_account(env()->ram_session_cap()); - env()->ram_session()->transfer_quota(ram.cap(), CHILD_QUOTA); - - /* register default exception handler */ - cpu.exception_sigh(sigh); - - /* register handler for unresolvable page faults */ - Region_map_client address_space(pd.address_space()); - address_space.fault_handler(sigh); - } - } _resources; - - Genode::Child::Initial_thread _initial_thread; - - /* - * The order of the following members is important. The services must - * appear before the child to ensure the correct order of destruction. - * I.e., the services must remain alive until the child has stopped - * executing. Otherwise, the child may hand out already destructed - * local services when dispatching an incoming session call. - */ - Genode::Rom_connection _elf; - Genode::Parent_service _log_service; - Genode::Parent_service _rm_service; - Genode::Region_map_client _address_space { _resources.pd.address_space() }; - Genode::Child _child; + Env &_env; + size_t const _ram_quota = 1024*1024; + Binary_name const _binary_name; + Signal_context_capability _sigh; + Parent_service _cpu_service { _env, Cpu_session::service_name() }; + Parent_service _ram_service { _env, Ram_session::service_name() }; + Parent_service _pd_service { _env, Pd_session::service_name() }; + Parent_service _log_service { _env, Log_session::service_name() }; + Parent_service _rom_service { _env, Rom_session::service_name() }; + Child _child; public: /** * Constructor */ - Test_child(Genode::Rpc_entrypoint &ep, - char const *elf_name, + Test_child(Env &env, Name const &binary_name, Genode::Signal_context_capability sigh) : - _resources(sigh, elf_name), - _initial_thread(_resources.cpu, _resources.pd, elf_name), - _elf(elf_name), - _log_service("LOG"), _rm_service("RM"), - _child(_elf.dataspace(), Genode::Dataspace_capability(), - _resources.pd, _resources.pd, - _resources.ram, _resources.ram, - _resources.cpu, _initial_thread, - *Genode::env()->rm_session(), _address_space, ep, *this) + _env(env), _binary_name(binary_name), _sigh(sigh), + _child(_env.rm(), _env.ep().rpc_ep(), *this) { } @@ -116,138 +97,102 @@ class Test_child : public Genode::Child_policy ** Child-policy interface ** ****************************/ - const char *name() const { return "child"; } + Name name() const override { return "child"; } - Genode::Service *resolve_session_request(const char *service, const char *) + Binary_name binary_name() const override { return _binary_name; } + + Ram_session &ref_ram() override { return _env.ram(); } + Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); } + + void init(Ram_session &ram, Ram_session_capability ram_cap) override { - /* forward white-listed session requests to our parent */ - return !Genode::strcmp(service, "LOG") ? &_log_service - : !Genode::strcmp(service, "RM") ? &_rm_service - : 0; + ram.ref_account(ref_ram_cap()); + ref_ram().transfer_quota(ram_cap, _ram_quota); } - void filter_session_args(const char *service, - char *args, Genode::size_t args_len) + void init(Cpu_session &cpu, Cpu_session_capability) override { - /* define session label for sessions forwarded to our parent */ - Genode::Arg_string::set_arg_string(args, args_len, "label", "child"); + /* register default exception handler */ + cpu.exception_sigh(_sigh); + } + + void init(Pd_session &pd, Pd_session_capability) override + { + /* register handler for unresolvable page faults */ + Region_map_client address_space(pd.address_space()); + address_space.fault_handler(_sigh); + } + + Service &resolve_session_request(Service::Name const &service, + Session_state::Args const &args) override + { + if (service == Cpu_session::service_name()) return _cpu_service; + if (service == Ram_session::service_name()) return _ram_service; + if (service == Pd_session::service_name()) return _pd_service; + if (service == Log_session::service_name()) return _log_service; + if (service == Rom_session::service_name()) return _rom_service; + + throw Parent::Service_denied(); + } + + void filter_session_args(Service::Name const &, + char *args, size_t args_len) override + { + /* prefix session label */ + Session_label const orig(label_from_args(args)); + Arg_string::set_arg_string(args, args_len, "label", + prefixed_label(name(), orig).string()); } }; -void faulting_child_test() +struct Faulting_child_test { - using namespace Genode; + static char const *name() { return "failure detection in immediate child"; } - log("-- exercise failure detection of immediate child --"); + Lazy_volatile_object _child; - /* - * Entry point used for serving the parent interface - */ - enum { STACK_SIZE = 8*1024 }; - Cap_connection cap; - Rpc_entrypoint ep(&cap, STACK_SIZE, "child"); - - /* - * Signal receiver and signal context for signals originating from the - * children's CPU-session and RM session. - */ - Signal_receiver sig_rec; - Signal_context sig_ctx; - - /* - * Iteratively start a faulting program and detect the faults - */ - for (int i = 0; i < 5; i++) { - - log("create child ", i); - - /* create and start child process */ - Test_child child(ep, "test-segfault", sig_rec.manage(&sig_ctx)); - - log("wait_for_signal"); - - - wait_for_signal_for_context(sig_rec, sig_ctx); - - sig_rec.dissolve(&sig_ctx); - - /* - * When finishing the loop iteration, the local variables including - * 'child' will get destructed. A new child will be created at the - * beginning of the next iteration. - */ + void start_iteration(Env &env, Signal_context_capability fault_sigh) + { + _child.construct(env, "test-segfault", fault_sigh); } - - log(""); -} +}; /****************************************************************** ** Test for detecting failures in a child started by the loader ** ******************************************************************/ -void faulting_loader_child_test() +struct Faulting_loader_child_test { - using namespace Genode; + static char const *name() { return "failure detection in loaded child"; } - log("-- exercise failure detection of loaded child --"); + Lazy_volatile_object loader; - /* - * Signal receiver and signal context for receiving faults originating from - * the loader subsystem. - */ - static Signal_receiver sig_rec; - Signal_context sig_ctx; - - for (int i = 0; i < 5; i++) { - - log("create loader session ", i); - - Loader::Connection loader(1024*1024); + void start_iteration(Env &env, Signal_context_capability fault_sigh) + { + loader.construct(env, 1024*1024); /* register fault handler at loader session */ - loader.fault_sigh(sig_rec.manage(&sig_ctx)); + loader->fault_sigh(fault_sigh); /* start subsystem */ - loader.start("test-segfault"); - - wait_for_signal_for_context(sig_rec, sig_ctx); - - sig_rec.dissolve(&sig_ctx); + loader->start("test-segfault"); } - - log(""); -} +}; /*********************************************************************** ** Test for detecting failures in a grandchild started by the loader ** ***********************************************************************/ -void faulting_loader_grand_child_test() +struct Faulting_loader_grand_child_test { - using namespace Genode; + static char const *name() { return "failure detection of loaded grand child"; } - log("-- exercise failure detection of loaded grand child --"); - - /* - * Signal receiver and signal context for receiving faults originating from - * the loader subsystem. - */ - static Signal_receiver sig_rec; - Signal_context sig_ctx; - - for (int i = 0; i < 5; i++) { - - log("create loader session ", i); - - Loader::Connection loader(2024*1024); - - /* - * Install init config for subsystem into the loader session - */ - char const *config = + static char const *config() + { + return "\n" " \n" " \n" @@ -261,50 +206,74 @@ void faulting_loader_grand_child_test() " \n" " \n" ""; - - size_t config_size = strlen(config); - - Dataspace_capability config_ds = - loader.alloc_rom_module("config", config_size); - - char *config_ds_addr = env()->rm_session()->attach(config_ds); - memcpy(config_ds_addr, config, config_size); - env()->rm_session()->detach(config_ds_addr); - - loader.commit_rom_module("config"); - - /* register fault handler at loader session */ - loader.fault_sigh(sig_rec.manage(&sig_ctx)); - - /* start subsystem */ - loader.start("init", "init"); - - wait_for_signal_for_context(sig_rec, sig_ctx); - - sig_rec.dissolve(&sig_ctx); } - log(""); -} + static size_t config_size() { return strlen(config()); } + + Lazy_volatile_object loader; + + void start_iteration(Env &env, Signal_context_capability fault_sigh) + { + loader.construct(env, 2*1024*1024); + + /* import config into loader session */ + { + Attached_dataspace ds(loader->alloc_rom_module("config", config_size())); + memcpy(ds.local_addr(), config(), config_size()); + loader->commit_rom_module("config"); + } + + /* register fault handler at loader session */ + loader->fault_sigh(fault_sigh); + + /* start subsystem */ + loader->start("init", "init"); + } +}; -/****************** - ** Main program ** - ******************/ - -int main(int argc, char **argv) +struct Main { - using namespace Genode; + Env &_env; - log("--- fault_detection test started ---"); + Lazy_volatile_object > _test_1; + Lazy_volatile_object > _test_2; + Lazy_volatile_object > _test_3; - faulting_child_test(); + Signal_handler
_test_1_finished_handler { + _env.ep(), *this, &Main::_handle_test_1_finished }; - faulting_loader_child_test(); + Signal_handler
_test_2_finished_handler { + _env.ep(), *this, &Main::_handle_test_2_finished }; - faulting_loader_grand_child_test(); + Signal_handler
_test_3_finished_handler { + _env.ep(), *this, &Main::_handle_test_3_finished }; - log("--- finished fault_detection test ---"); - return 0; -} + void _handle_test_1_finished() + { + _test_1.destruct(); + _test_2.construct(_env, _test_2_finished_handler); + } + + void _handle_test_2_finished() + { + _test_2.destruct(); + _test_3.construct(_env, _test_3_finished_handler); + } + + void _handle_test_3_finished() + { + _test_3.destruct(); + log("--- finished fault_detection test ---"); + _env.parent().exit(0); + } + + Main(Env &env) : _env(env) + { + _test_1.construct(_env, _test_1_finished_handler); + } +}; + + +void Component::construct(Env &env) { static Main main(env); } diff --git a/repos/os/src/test/report_rom/main.cc b/repos/os/src/test/report_rom/main.cc index 7b92be466..800e2a5d1 100644 --- a/repos/os/src/test/report_rom/main.cc +++ b/repos/os/src/test/report_rom/main.cc @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -20,7 +21,7 @@ #define ASSERT(cond) \ if (!(cond)) { \ Genode::error("assertion ", #cond, " failed"); \ - return -2; } + throw -2; } static void report_brightness(Genode::Reporter &reporter, int value) @@ -30,7 +31,7 @@ static void report_brightness(Genode::Reporter &reporter, int value) } -int main(int argc, char **argv) +void Component::construct(Genode::Env &env) { using namespace Genode; @@ -70,7 +71,7 @@ int main(int argc, char **argv) brightness_reporter.enabled(false); /* give report_rom some time to close the report session */ - static Timer::Connection timer; + Timer::Connection timer; timer.msleep(250); brightness_rom.update(); @@ -89,7 +90,7 @@ int main(int argc, char **argv) Reporter again("brightness"); again.enabled(true); error("expected Service_denied"); - return -3; + throw -3; } catch (Genode::Parent::Service_denied) { log("ROM client: catched Parent::Service_denied - OK"); } @@ -98,5 +99,5 @@ int main(int argc, char **argv) sig_rec.dissolve(&sig_ctx); - return 0; + env.parent().exit(0); } diff --git a/repos/os/src/test/resource_yield/main.cc b/repos/os/src/test/resource_yield/main.cc index 5e366980b..158218763 100644 --- a/repos/os/src/test/resource_yield/main.cc +++ b/repos/os/src/test/resource_yield/main.cc @@ -27,11 +27,11 @@ /* Genode includes */ #include +#include +#include #include #include -#include #include -#include #include @@ -51,32 +51,31 @@ class Child struct Ram_chunk : Genode::List::Element { + Genode::Env &env; + size_t const size; Genode::Ram_dataspace_capability ds_cap; - Ram_chunk(size_t size) + Ram_chunk(Genode::Env &env, size_t size) : - size(size), - ds_cap(Genode::env()->ram_session()->alloc(size)) + env(env),size(size), ds_cap(env.ram().alloc(size)) { } - ~Ram_chunk() - { - Genode::env()->ram_session()->free(ds_cap); - } + ~Ram_chunk() { env.ram().free(ds_cap); } }; - bool const _expand; - Genode::List _ram_chunks; - Timer::Connection _timer; - Genode::Signal_receiver _sig_rec; - Genode::Signal_dispatcher _periodic_timeout_dispatcher; - Genode::Signal_dispatcher _yield_dispatcher; - unsigned long const _period_ms; + Genode::Env &_env; + Genode::Heap _heap { _env.ram(), _env.rm() }; + bool const _expand; + Genode::List _ram_chunks; + Timer::Connection _timer { _env }; + Genode::Signal_handler _periodic_timeout_handler; + Genode::Signal_handler _yield_handler; + unsigned long const _period_ms; - void _dispatch_periodic_timeout(unsigned); - void _dispatch_yield(unsigned); + void _handle_periodic_timeout(); + void _handle_yield(); void _schedule_next_timeout() { @@ -85,16 +84,16 @@ class Child public: - Child(); + Child(Genode::Env &, Genode::Xml_node); void main(); }; -void Child::_dispatch_periodic_timeout(unsigned) +void Child::_handle_periodic_timeout() { size_t const chunk_size = 1024*1024; - if (Genode::env()->ram_session()->avail() < chunk_size) { + if (_env.ram().avail() < chunk_size) { if (_expand) { Genode::log("quota consumed, request additional resources"); @@ -112,7 +111,7 @@ void Child::_dispatch_periodic_timeout(unsigned) } /* perform allocation and remember chunk in list */ - _ram_chunks.insert(new (Genode::env()->heap()) Ram_chunk(chunk_size)); + _ram_chunks.insert(new (_heap) Ram_chunk(_env, chunk_size)); Genode::log("allocated chunk of ", chunk_size / 1024, " KiB"); @@ -120,12 +119,12 @@ void Child::_dispatch_periodic_timeout(unsigned) } -void Child::_dispatch_yield(unsigned) +void Child::_handle_yield() { using namespace Genode; /* request yield request arguments */ - Parent::Resource_args const args = env()->parent()->yield_request(); + Parent::Resource_args const args = _env.parent().yield_request(); log("yield request: ", args.string()); @@ -144,63 +143,37 @@ void Child::_dispatch_yield(unsigned) size_t const chunk_size = chunk->size; _ram_chunks.remove(chunk); - destroy(env()->heap(), chunk); + destroy(_heap, chunk); released_quota += chunk_size; log("released chunk of ", chunk_size, " bytes"); } /* acknowledge yield request */ - env()->parent()->yield_response(); + _env.parent().yield_response(); _schedule_next_timeout(); } -static inline unsigned long read_period_ms_from_config() -{ - unsigned long period_ms = 500; - if (Genode::config()->xml_node().has_attribute("period_ms")) - Genode::config()->xml_node().attribute("period_ms").value(&period_ms); - return period_ms; -} - - -Child::Child() +Child::Child(Genode::Env &env, Genode::Xml_node config) : - _expand(Genode::config()->xml_node().attribute_value("expand", false)), - _periodic_timeout_dispatcher(_sig_rec, *this, - &Child::_dispatch_periodic_timeout), - _yield_dispatcher(_sig_rec, *this, - &Child::_dispatch_yield), - _period_ms(read_period_ms_from_config()) + _env(env), + _expand(config.attribute_value("expand", false)), + _periodic_timeout_handler(_env.ep(), *this, &Child::_handle_periodic_timeout), + _yield_handler(_env.ep(), *this, &Child::_handle_yield), + _period_ms(config.attribute_value("period_ms", 500UL)) { /* register yield signal handler */ - Genode::env()->parent()->yield_sigh(_yield_dispatcher); + _env.parent().yield_sigh(_yield_handler); /* register timeout signal handler and schedule periodic timeouts */ - _timer.sigh(_periodic_timeout_dispatcher); + _timer.sigh(_periodic_timeout_handler); _schedule_next_timeout(); } -void Child::main() -{ - using namespace Genode; - - for (;;) { - Signal sig = _sig_rec.wait_for_signal(); - - Signal_dispatcher_base *dispatcher = - dynamic_cast(sig.context()); - - if (dispatcher) - dispatcher->dispatch(sig.num()); - } -} - - /***************** ** Parent role ** *****************/ @@ -209,48 +182,100 @@ void Child::main() * The parent grants resource requests as long as it has free resources. * Once in a while, it politely requests the child to yield resources. */ -class Parent : Genode::Slave_policy +class Parent : Genode::Slave::Policy { private: - /** - * Return singleton entrypoint instance - * - * The entrypoint cannot be a regular member because we need to pass - * it into the constructor of the 'Slave_policy' base class. - */ - static Genode::Rpc_entrypoint &_entrypoint(); + Genode::Env &_env; typedef Genode::size_t size_t; - size_t const slave_quota = 10*1024*1024; + enum { SLAVE_QUOTA = 10*1024*1024 }; - Genode::Slave _slave = { _entrypoint(), *this, slave_quota }; + Genode::Child _child = { _env.rm(), _env.ep().rpc_ep(), *this }; - Timer::Connection _timer; + Timer::Connection _timer { _env }; Genode::Lock _yield_blockade; void _print_status() { - Genode::log("quota: ", _slave.ram().quota() / 1024, " KiB " - "used: ", _slave.ram().used() / 1024, " KiB"); + Genode::log("quota: ", _child.ram().quota() / 1024, " KiB " + "used: ", _child.ram().used() / 1024, " KiB"); } + size_t _used_ram_prior_yield = 0; + + /* perform the test three times */ + unsigned _cnt = 3; + + unsigned const _wait_secs = 5; + + unsigned _wait_cnt = 0; + + enum State { WAIT, YIELD_REQUESTED, YIELD_GOT_RESPONSE }; + State _state = WAIT; + + void _schedule_one_second_timeout() + { + Genode::log("wait ", _wait_cnt, "/", _wait_secs); + _timer.trigger_once(1000*1000); + } + + void _init() + { + _state = WAIT; + _wait_cnt = 0; + _schedule_one_second_timeout(); + } + + void _request_yield() + { + /* remember quantum of resources used by the child */ + _used_ram_prior_yield = _child.ram().used(); + + Genode::log("request yield (ram prior yield: ", _used_ram_prior_yield); + + /* issue yield request */ + Genode::Parent::Resource_args yield_args("ram_quota=5M"); + _child.yield(yield_args); + + _state = YIELD_REQUESTED; + } + + void _handle_timeout() + { + _print_status(); + _wait_cnt++; + if (_wait_cnt >= _wait_secs) { + _request_yield(); + } else { + _schedule_one_second_timeout(); + } + } + + Genode::Signal_handler _timeout_handler { + _env.ep(), *this, &Parent::_handle_timeout }; + public: + class Insufficient_yield { }; + /** * Constructor */ - Parent() + Parent(Genode::Env &env) : - Genode::Slave_policy("test-resource_yield", _entrypoint(), - Genode::env()->ram_session()) + Genode::Slave::Policy(Label(), "test-resource_yield", env.ep().rpc_ep(), + env.rm(), env.ram_session_cap(), SLAVE_QUOTA), + _env(env) { configure(""); + + _timer.sigh(_timeout_handler); + _init(); } - int main(); /**************************** ** Slave_policy interface ** @@ -258,95 +283,39 @@ class Parent : Genode::Slave_policy char const **_permitted_services() const { - static char const *services[] = { "RM", "LOG", "Timer" }; + static char const *services[] = { "RAM", "PD", "CPU", "ROM", "LOG", "Timer" }; return services; } void yield_response() { - _yield_blockade.unlock(); + Genode::log("got yield response"); + _state = YIELD_GOT_RESPONSE; - /* - * At this point, the ownership of '_yield_blockade' will be passed - * to the main program. By trying to aquire it here, we block until - * the main program is ready. - * - * This way, we ensure that the main program validates the - * statistics before the 'yield_response' RPC call returns. - * Otherwise, the child might allocate new resources before the - * main program is able to see the amount of yielded resources. - */ - Genode::Lock::Guard guard(_yield_blockade); + _print_status(); + + /* validate that the amount of yielded resources matches the request */ + size_t const used_after_yield = _child.ram().used(); + if (used_after_yield + 5*1024*1024 > _used_ram_prior_yield) { + Genode::error("child has not yielded enough resources"); + throw Insufficient_yield(); + } + + if (_cnt-- > 0) { + _init(); + } else { + Genode::log("--- test-resource_yield finished ---"); + _env.parent().exit(0); + } } - }; -Genode::Rpc_entrypoint &Parent::_entrypoint() -{ - using namespace Genode; - static Cap_connection cap; - size_t const stack_size = sizeof(addr_t)*2*1024; - static Rpc_entrypoint ep(&cap, stack_size, "ep", false); - return ep; -} +/*************** + ** Component ** + ***************/ - -int Parent::main() -{ - using namespace Genode; - - _entrypoint().activate(); - - /* perform the test three times */ - for (unsigned j = 0; j < 3; j++) { - - /* wait five seconds and observe growth of resource usage */ - for (unsigned i = 0; i < 5; i++) { - _timer.msleep(1000); - _print_status(); - } - - /* remember quantum of resources used by the child */ - size_t const used_prior_yield = _slave.ram().used(); - - /* issue yield request */ - Genode::Parent::Resource_args yield_args("ram_quota=5M"); - _slave.yield(yield_args); - - /* - * Synchronously wait for a yield response. Note that a careful parent - * would never trust its child to comply to the yield request. - */ - log("wait for yield response"); - _yield_blockade.lock(); - _yield_blockade.lock(); - log("got yield response"); - - _print_status(); - - /* validate that the amount of yielded resources matches the request */ - size_t const used_after_yield = _slave.ram().used(); - if (used_after_yield + 5*1024*1024 > used_prior_yield) { - error("child has not yielded enough resources"); - return -1; - } - - /* let the 'yield_response' RPC call return */ - _yield_blockade.unlock(); - } - - log("--- test-resource_yield finished ---"); - - return 0; -} - - -/****************** - ** Main program ** - ******************/ - -int main(int argc, char **argv) +void Component::construct(Genode::Env &env) { using namespace Genode; @@ -354,17 +323,14 @@ int main(int argc, char **argv) * Read value '' attribute to decide whether to perform * the child or the parent role. */ - bool const is_child = config()->xml_node().has_attribute("child") - && config()->xml_node().attribute_value("child", false); + static Attached_rom_dataspace config(env, "config"); + bool const is_child = config.xml().attribute_value("child", false); if (is_child) { log("--- test-resource_yield child role started ---"); - static ::Child child; - child.main(); - return -1; /* the child should never reach this point */ + static ::Child child(env, config.xml()); } else { log("--- test-resource_yield parent role started ---"); - static ::Parent parent; - return parent.main(); + static ::Parent parent(env); } } diff --git a/repos/os/src/test/signal/main.cc b/repos/os/src/test/signal/main.cc index 6a97ce3d0..babe01d30 100644 --- a/repos/os/src/test/signal/main.cc +++ b/repos/os/src/test/signal/main.cc @@ -11,12 +11,13 @@ * under the terms of the GNU General Public License version 2. */ +#include +#include #include #include #include #include #include -#include #include using namespace Genode; @@ -25,17 +26,17 @@ using namespace Genode; /** * Transmit signals in a periodic fashion */ -class Sender : Thread_deprecated<4096> +class Sender : Thread { private: - Signal_transmitter _transmitter; Timer::Connection _timer; /* timer connection for local use */ - unsigned _interval_ms; /* interval between signals in milliseconds */ + Signal_transmitter _transmitter; + unsigned const _interval_ms; /* interval between signals in milliseconds */ bool _stop; /* state for destruction protocol */ unsigned _submit_cnt; /* statistics */ bool _idle; /* suppress the submission of signals */ - bool _verbose; /* print activities */ + bool const _verbose; /* print activities */ /** * Sender thread submits signals every '_interval_ms' milliseconds @@ -68,10 +69,11 @@ class Sender : Thread_deprecated<4096> * \param interval_ms interval between signals * \param verbose print status information */ - Sender(Signal_context_capability context, + Sender(Env &env, Signal_context_capability context, unsigned interval_ms, bool verbose = true) : - Thread_deprecated("sender"), + Thread(env, "sender", 4096*sizeof(long)), + _timer(env), _transmitter(context), _interval_ms(interval_ms), _stop(false), @@ -110,20 +112,20 @@ class Sender : Thread_deprecated<4096> /** * Signal handler receives signals and takes some time to handle each */ -class Handler : Thread_deprecated<4096> +class Handler : Thread { private: - unsigned _dispatch_ms; /* time needed for dispatching a signal */ - unsigned _id; /* unique ID of signal handler for debug output */ - static unsigned _id_cnt; /* counter for producing unique IDs */ - Signal_receiver *_receiver; /* signal endpoint */ Timer::Connection _timer; /* timer connection for local use */ + unsigned const _dispatch_ms; /* time needed for dispatching a signal */ + unsigned const _id; /* unique ID of signal handler for debug output */ + static unsigned _id_cnt; /* counter for producing unique IDs */ + Signal_receiver &_receiver; /* signal endpoint */ bool _stop; /* state for destruction protocol */ unsigned _receive_cnt; /* number of received notifications */ unsigned _activation_cnt; /* number of invocations of the signal handler */ bool _idle; /* suppress the further handling of signals */ - bool _verbose; /* print status information */ + bool const _verbose; /* print status information */ /** * Signal handler needs '_dispatch_ms' milliseconds for each signal @@ -133,7 +135,7 @@ class Handler : Thread_deprecated<4096> while (!_stop) { if (!_idle) { - Signal signal = _receiver->wait_for_signal(); + Signal signal = _receiver.wait_for_signal(); if (_verbose) log("handler ", _id, " got ", signal.num(), " " @@ -158,9 +160,10 @@ class Handler : Thread_deprecated<4096> * \param dispatch_ms duration of signal-handler activity * \param verbose print status information */ - Handler(Signal_receiver *receiver, unsigned dispatch_ms, bool verbose = true) + Handler(Env &env, Signal_receiver &receiver, unsigned dispatch_ms, bool verbose = true) : - Thread_deprecated("handler"), + Thread(env, "handler", 4096*sizeof(long)), + _timer(env), _dispatch_ms(dispatch_ms), _id(++_id_cnt), _receiver(receiver), @@ -214,18 +217,6 @@ unsigned Handler::_id_cnt = 0; static unsigned test_cnt = 0; -/** - * Timer connection to be used by the main program - */ -static Timer::Connection timer; - - -/** - * Connection to CAP service used for allocating signal-context capabilities - */ -static Genode::Cap_connection cap; - - /** * Symbolic error codes */ @@ -257,7 +248,7 @@ class Id_signal_context : public Signal_context * submitted notifications on the sender side does not match the number of * notifications received at the signal handler. */ -static void fast_sender_test() +static void fast_sender_test(Env &env) { enum { SPEED = 10 }; enum { TEST_DURATION = 50*SPEED }; @@ -272,9 +263,12 @@ static void fast_sender_test() Signal_receiver receiver; Id_signal_context context_123(123); - Handler *handler = new (env()->heap()) Handler(&receiver, HANDLER_INTERVAL, false); - Sender *sender = new (env()->heap()) Sender(receiver.manage(&context_123), - SENDER_INTERVAL, false); + Heap heap(env.ram(), env.rm()); + Timer::Connection timer(env); + + Handler *handler = new (heap) Handler(env, receiver, HANDLER_INTERVAL, false); + Sender *sender = new (heap) Sender(env, receiver.manage(&context_123), + SENDER_INTERVAL, false); timer.msleep(TEST_DURATION); @@ -293,8 +287,8 @@ static void fast_sender_test() receiver.dissolve(&context_123); - destroy(env()->heap(), sender); - destroy(env()->heap(), handler); + destroy(heap, sender); + destroy(heap, handler); log("TEST ", test_cnt, " FINISHED"); } @@ -308,7 +302,7 @@ static void fast_sender_test() * Furthermore, if operating in non-descrete mode, the total number of sent and * handled notifications is checked. */ -static void multiple_handlers_test() +static void multiple_handlers_test(Env &env) { enum { SPEED = 10 }; enum { TEST_DURATION = 50*SPEED }; @@ -321,14 +315,16 @@ static void multiple_handlers_test() log("TEST ", ++test_cnt, ": one busy sender, ", (int)NUM_HANDLERS, " handlers"); log(""); + Heap heap(env.ram(), env.rm()); + Timer::Connection timer(env); Signal_receiver receiver; Handler *handler[NUM_HANDLERS]; for (int i = 0; i < NUM_HANDLERS; i++) - handler[i] = new (env()->heap()) Handler(&receiver, HANDLER_INTERVAL); + handler[i] = new (heap) Handler(env, receiver, HANDLER_INTERVAL); Id_signal_context context_123(123); - Sender *sender = new (env()->heap()) Sender(receiver.manage(&context_123), SENDER_INTERVAL); + Sender *sender = new (heap) Sender(env, receiver.manage(&context_123), SENDER_INTERVAL); timer.msleep(TEST_DURATION); @@ -375,9 +371,9 @@ static void multiple_handlers_test() /* cleanup */ receiver.dissolve(&context_123); - destroy(env()->heap(), sender); + destroy(heap, sender); for (int i = 0; i < NUM_HANDLERS; i++) - destroy(env()->heap(), handler[i]); + destroy(heap, handler[i]); log("TEST ", test_cnt, " FINISHED"); } @@ -390,7 +386,7 @@ static void multiple_handlers_test() * We produce and handle notifications as fast as possible via spinning * loops at the sender and handler side. */ -static void stress_test() +static void stress_test(Env &env) { enum { SPEED = 10 }; enum { DURATION_SECONDS = 5 }; @@ -400,12 +396,14 @@ static void stress_test() log("TEST ", ++test_cnt, ": stress test, busy signal transmission and handling"); log(""); + Timer::Connection timer(env); + Heap heap(env.ram(), env.rm()); Signal_receiver receiver; Id_signal_context context_123(123); - Handler *handler = new (env()->heap()) Handler(&receiver, 0, false); - Sender *sender = new (env()->heap()) Sender(receiver.manage(&context_123), - 0, false); + Handler *handler = new (heap) Handler(env, receiver, 0, false); + Sender *sender = new (heap) Sender(env, receiver.manage(&context_123), + 0, false); for (int i = 1; i <= DURATION_SECONDS; i++) { log(i, "/", (int)DURATION_SECONDS); @@ -433,14 +431,14 @@ static void stress_test() throw Test_failed_with_unequal_sent_and_received_signals(); receiver.dissolve(&context_123); - destroy(env()->heap(), sender); - destroy(env()->heap(), handler); + destroy(heap, sender); + destroy(heap, handler); log("TEST ", test_cnt, " FINISHED"); } -static void lazy_receivers_test() +static void lazy_receivers_test(Env &env) { log(""); log("TEST ", ++test_cnt, ": lazy and out-of-order signal reception test"); @@ -486,19 +484,22 @@ static void lazy_receivers_test() /** * Try correct initialization and cleanup of receiver/context */ -static void check_context_management() +static void check_context_management(Env &env) { Id_signal_context *context; Signal_receiver *rec; Signal_context_capability cap; + Timer::Connection timer(env); + Heap heap(env.ram(), env.rm()); + /* setup receiver side */ - context = new (env()->heap()) Id_signal_context(321); - rec = new (env()->heap()) Signal_receiver; + context = new (heap) Id_signal_context(321); + rec = new (heap) Signal_receiver; cap = rec->manage(context); /* spawn sender */ - Sender *sender = new (env()->heap()) Sender(cap, 500); + Sender *sender = new (heap) Sender(env, cap, 500); /* stop sender after timeout */ timer.msleep(1000); @@ -520,10 +521,10 @@ static void check_context_management() sender->idle(); log("destroy sender"); - destroy(env()->heap(), sender); + destroy(heap, sender); - destroy(env()->heap(), context); - destroy(env()->heap(), rec); + destroy(heap, context); + destroy(heap, rec); } @@ -558,11 +559,13 @@ class Signal_context_destroyer : public Thread_deprecated<4096> }; -static void synchronized_context_destruction_test() +static void synchronized_context_destruction_test(Env &env) { Signal_receiver receiver; + Timer::Connection timer(env); + static Heap heap(env.ram(), env.rm()); - Signal_context *context = new (env()->heap()) Signal_context; + Signal_context *context = new (heap) Signal_context; Signal_transmitter transmitter(receiver.manage(context)); transmitter.submit(); @@ -595,8 +598,9 @@ static void synchronized_context_destruction_test() } -static void many_managed_contexts() +static void many_managed_contexts(Env &env) { + static Heap heap(env.ram(), env.rm()); for (unsigned round = 0; round < 10; ++round) { unsigned const num_contexts = 200 + 5*round; @@ -605,7 +609,7 @@ static void many_managed_contexts() Signal_receiver rec; for (unsigned i = 0; i < num_contexts; ++i) { - Id_signal_context *context = new (env()->heap()) Id_signal_context(i); + Id_signal_context *context = new (heap) Id_signal_context(i); if (!rec.manage(context).valid()) { error("failed to manage signal context"); sleep_forever(); @@ -617,21 +621,18 @@ static void many_managed_contexts() } -/** - * Main program - */ -int main(int, char **) +void Component::construct(Genode::Env &env) { log("--- signalling test ---"); - fast_sender_test(); - multiple_handlers_test(); - stress_test(); - lazy_receivers_test(); - check_context_management(); - synchronized_context_destruction_test(); - many_managed_contexts(); + fast_sender_test(env); + multiple_handlers_test(env); + stress_test(env); + lazy_receivers_test(env); + check_context_management(env); + synchronized_context_destruction_test(env); + many_managed_contexts(env); log("--- signalling test finished ---"); - return 0; + env.parent().exit(0); }