From c2af646ad8c245eb67b1ba1d1dc2de715ce9824d Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Tue, 28 Jan 2014 14:07:36 +0100 Subject: [PATCH] noux: Noux_connection::context_area_rm_session() This enables a forked process to update the capability of its context area RM session. ref #989 --- ports/include/noux_session/client.h | 5 + ports/include/noux_session/noux_session.h | 13 +- ports/src/lib/libc_noux/plugin.cc | 10 + ports/src/noux/child.h | 5 + ports/src/noux/dataspace_registry.h | 11 + ports/src/noux/local_rm_service.h | 6 + ports/src/noux/rm_session_component.h | 534 ++++++++++++---------- 7 files changed, 334 insertions(+), 250 deletions(-) diff --git a/ports/include/noux_session/client.h b/ports/include/noux_session/client.h index 3844a90fd..b43cc0c8e 100644 --- a/ports/include/noux_session/client.h +++ b/ports/include/noux_session/client.h @@ -48,6 +48,11 @@ namespace Noux { { return call(start_fd); } + + Rm_session_capability lookup_rm_session(addr_t const addr) + { + return call(addr); + } }; } diff --git a/ports/include/noux_session/noux_session.h b/ports/include/noux_session/noux_session.h index 106108134..810645ad4 100644 --- a/ports/include/noux_session/noux_session.h +++ b/ports/include/noux_session/noux_session.h @@ -17,6 +17,7 @@ #include #include #include +#include #define NOUX_DECL_SYSCALL_NAME(name) \ case SYSCALL_##name: return #name; @@ -33,6 +34,13 @@ namespace Noux { virtual Dataspace_capability sysio_dataspace() = 0; + /** + * Return leaf RM session that covers a given address + * + * \param addr address that is covered by the requested RM session + */ + virtual Rm_session_capability lookup_rm_session(addr_t const addr) = 0; + enum Syscall { SYSCALL_WRITE, SYSCALL_READ, @@ -154,10 +162,13 @@ namespace Noux { *********************/ GENODE_RPC(Rpc_sysio_dataspace, Dataspace_capability, sysio_dataspace); + GENODE_RPC(Rpc_lookup_rm_session, Rm_session_capability, + lookup_rm_session, addr_t); GENODE_RPC(Rpc_syscall, bool, syscall, Syscall); GENODE_RPC(Rpc_next_open_fd, int, next_open_fd, int); - GENODE_RPC_INTERFACE(Rpc_sysio_dataspace, Rpc_syscall, Rpc_next_open_fd); + GENODE_RPC_INTERFACE(Rpc_sysio_dataspace, Rpc_lookup_rm_session, + Rpc_syscall, Rpc_next_open_fd); }; } diff --git a/ports/src/lib/libc_noux/plugin.cc b/ports/src/lib/libc_noux/plugin.cc index 67b75d082..56cfb5feb 100644 --- a/ports/src/lib/libc_noux/plugin.cc +++ b/ports/src/lib/libc_noux/plugin.cc @@ -86,6 +86,16 @@ class Noux_connection _sysio = _obtain_sysio(); } + /** + * Return the capability of the local context-area RM session + */ + Genode::Rm_session_capability context_area_rm_session() + { + using namespace Genode; + addr_t const addr = Native_config::context_area_virtual_base(); + return _connection.lookup_rm_session(addr); + } + Noux::Session *session() { return &_connection; } Noux::Sysio *sysio() { return _sysio; } }; diff --git a/ports/src/noux/child.h b/ports/src/noux/child.h index 5b2a8b21e..d271fb011 100644 --- a/ports/src/noux/child.h +++ b/ports/src/noux/child.h @@ -425,6 +425,11 @@ namespace Noux { return _sysio_ds.cap(); } + Rm_session_capability lookup_rm_session(addr_t const addr) + { + return _resources.rm.lookup_rm_session(addr); + } + bool syscall(Syscall sc); int next_open_fd(int start_fd) diff --git a/ports/src/noux/dataspace_registry.h b/ports/src/noux/dataspace_registry.h index c98e26b7c..38798d2ae 100644 --- a/ports/src/noux/dataspace_registry.h +++ b/ports/src/noux/dataspace_registry.h @@ -103,6 +103,17 @@ namespace Noux { * \param len length of source buffer in bytes */ virtual void poke(addr_t dst_offset, void const *src, size_t len) = 0; + + /** + * Return leaf RM session that covers a given address + * + * \param addr address that is covered by the requested RM session + */ + virtual Rm_session_capability lookup_rm_session(addr_t const addr) + { + /* by default a dataspace is no sub RM, so return invalid */ + return Rm_session_capability(); + } }; diff --git a/ports/src/noux/local_rm_service.h b/ports/src/noux/local_rm_service.h index 884fdd9bb..bb6c75d8a 100644 --- a/ports/src/noux/local_rm_service.h +++ b/ports/src/noux/local_rm_service.h @@ -85,6 +85,12 @@ namespace Noux { } _sub_rm->poke(dst_offset, src, len); } + + Rm_session_capability lookup_rm_session(addr_t const addr) + { + /* the dataspace is a sub RM, so traverse into it */ + return _sub_rm->lookup_rm_session(addr); + } }; diff --git a/ports/src/noux/rm_session_component.h b/ports/src/noux/rm_session_component.h index f7ea7d805..a945da1d5 100644 --- a/ports/src/noux/rm_session_component.h +++ b/ports/src/noux/rm_session_component.h @@ -1,6 +1,7 @@ /* * \brief RM session implementation used by Noux processes * \author Norman Feske + * \author Martin Stein * \date 2012-02-22 * * The custom RM implementation is used for recording all RM regions attached @@ -22,298 +23,333 @@ #include #include -namespace Noux { - +namespace Noux +{ static bool verbose_attach = false; - class Rm_session_component : public Rpc_object - { - private: + /** + * Server sided back-end of an RM session of a Noux process + */ + class Rm_session_component; +} - /** - * Record of an attached dataspace - */ - struct Region : List::Element, Dataspace_user - { - Rm_session_component &rm; - Dataspace_capability ds; - size_t size; - off_t offset; - addr_t local_addr; +class Noux::Rm_session_component : public Rpc_object +{ + private: - Region(Rm_session_component &rm, - Dataspace_capability ds, size_t size, - off_t offset, addr_t local_addr) - : - rm(rm), ds(ds), size(size), offset(offset), - local_addr(local_addr) - { } + /** + * Record of an attached dataspace + */ + struct Region : List::Element, Dataspace_user + { + Rm_session_component &rm; + Dataspace_capability ds; + size_t size; + off_t offset; + addr_t local_addr; - /** - * Return true if region contains specified address - */ - bool contains(addr_t addr) const - { - return (addr >= local_addr) - && (addr < local_addr + size); - } - - Region *next_region() - { - return List::Element::next(); - } - - inline void dissolve(Dataspace_info &ds); - }; - - Lock _region_lock; - List _regions; - - Region *_lookup_region_by_addr(addr_t local_addr) - { - Region *curr = _regions.first(); - for (; curr; curr = curr->next_region()) { - if (curr->contains(local_addr)) - return curr; - } - return 0; - } - - /** - * Wrapped RM session at core - */ - Rm_connection _rm; - - Dataspace_registry &_ds_registry; - - public: - - Rm_session_component(Dataspace_registry &ds_registry, - addr_t start = ~0UL, size_t size = 0) + Region(Rm_session_component &rm, + Dataspace_capability ds, size_t size, + off_t offset, addr_t local_addr) : - _rm(start, size), _ds_registry(ds_registry) + rm(rm), ds(ds), size(size), offset(offset), + local_addr(local_addr) { } - ~Rm_session_component() - { - Region *curr; - while ((curr = _regions.first())) - detach(curr->local_addr); - } - /** - * Replay attachments onto specified RM session - * - * \param dst_ram backing store used for allocating the - * the copies of RAM dataspaces - * \param ds_registry dataspace registry used for keeping track - * of newly created dataspaces - * \param ep entrypoint used to serve the RPC interface - * of forked managed dataspaces + * Return true if region contains specified address */ - void replay(Ram_session_capability dst_ram, - Rm_session_capability dst_rm, - Dataspace_registry &ds_registry, - Rpc_entrypoint &ep) + bool contains(addr_t addr) const { - Lock::Guard guard(_region_lock); - for (Region *curr = _regions.first(); curr; curr = curr->next_region()) { - - Dataspace_capability ds; - - Object_pool::Guard info(_ds_registry.lookup_info(curr->ds)); - - if (info) { - - ds = info->fork(dst_ram, ds_registry, ep); - - /* - * XXX We could detect dataspaces that are attached - * more than once. For now, we create a new fork - * for each attachment. - */ - - } else { - - PERR("replay: missing ds_info for dataspace at addr 0x%lx", - curr->local_addr); - - /* - * If the dataspace is not a RAM dataspace, assume that - * it's a ROM dataspace. - * - * XXX Handle ROM dataspaces explicitly. For once, we - * need to make sure that they remain available - * until the child process exits even if the parent - * process exits earlier. Furthermore, we would - * like to detect unexpected dataspaces. - */ - ds = curr->ds; - } - - if (!ds.valid()) { - PERR("replay: Error while forking dataspace"); - continue; - } - - Rm_session_client(dst_rm).attach(ds, curr->size, - curr->offset, - true, - curr->local_addr); - } + return (addr >= local_addr) && (addr < local_addr + size); } - void poke(addr_t dst_addr, void const *src, size_t len) + Region *next_region() { - Dataspace_capability ds_cap; - addr_t local_addr; + return List::Element::next(); + } - { - Lock::Guard guard(_region_lock); + inline void dissolve(Dataspace_info &ds); + }; - Region *region = _lookup_region_by_addr(dst_addr); - if (!region) { - PERR("poke: no region at 0x%lx", dst_addr); - return; - } + Lock _region_lock; + List _regions; + + Region *_lookup_region_by_addr(addr_t local_addr) + { + Region *curr = _regions.first(); + for (; curr; curr = curr->next_region()) { + if (curr->contains(local_addr)) + return curr; + } + return 0; + } + + /** + * Wrapped RM session at core + */ + Rm_connection _rm; + + Dataspace_registry &_ds_registry; + + public: + + /** + * Constructor + */ + Rm_session_component(Dataspace_registry & ds_registry, + addr_t start = ~0UL, size_t size = 0) + : + _rm(start, size), _ds_registry(ds_registry) + { } + + /** + * Destructor + */ + ~Rm_session_component() + { + Region *curr; + while ((curr = _regions.first())) + detach(curr->local_addr); + } + + /** + * Return leaf RM session that covers a given address + * + * \param addr address that is covered by the requested RM session + */ + Rm_session_capability lookup_rm_session(addr_t const addr) + { + /* if there's no region that could be a sub RM then we're a leaf */ + Region * const region = _lookup_region_by_addr(addr); + if (!region) { return cap(); } + + /* if there is no info for the region it can't be a sub RM */ + Dataspace_capability ds_cap = region->ds; + typedef Object_pool::Guard Info_guard; + Info_guard info(_ds_registry.lookup_info(ds_cap)); + if (!info) { return cap(); } + + /* ask the dataspace info for an appropriate sub RM */ + addr_t const region_base = region->local_addr; + addr_t const region_off = region->offset; + addr_t const sub_addr = addr - region_base + region_off; + Rm_session_capability sub_rm = info->lookup_rm_session(sub_addr); + + /* if the result is invalid the dataspace is no sub RM */ + if (!sub_rm.valid()) { return cap(); } + return sub_rm; + } + + /** + * Replay attachments onto specified RM session + * + * \param dst_ram backing store used for allocating the + * the copies of RAM dataspaces + * \param ds_registry dataspace registry used for keeping track + * of newly created dataspaces + * \param ep entrypoint used to serve the RPC interface + * of forked managed dataspaces + */ + void replay(Ram_session_capability dst_ram, + Rm_session_capability dst_rm, + Dataspace_registry &ds_registry, + Rpc_entrypoint &ep) + { + Lock::Guard guard(_region_lock); + for (Region *curr = _regions.first(); curr; curr = curr->next_region()) { + + Dataspace_capability ds; + + Object_pool::Guard info(_ds_registry.lookup_info(curr->ds)); + + if (info) { + + ds = info->fork(dst_ram, ds_registry, ep); /* - * Test if start and end address occupied by the object - * type refers to the same region. + * XXX We could detect dataspaces that are attached + * more than once. For now, we create a new fork + * for each attachment. */ - if (region != _lookup_region_by_addr(dst_addr + len - 1)) { - PERR("attempt to write beyond region boundary"); - return; - } - if (region->offset) { - PERR("poke: writing to region with offset is not supported"); - return; - } + } else { - ds_cap = region->ds; - local_addr = region->local_addr; + PERR("replay: missing ds_info for dataspace at addr 0x%lx", + curr->local_addr); + + /* + * If the dataspace is not a RAM dataspace, assume that + * it's a ROM dataspace. + * + * XXX Handle ROM dataspaces explicitly. For once, we + * need to make sure that they remain available + * until the child process exits even if the parent + * process exits earlier. Furthermore, we would + * like to detect unexpected dataspaces. + */ + ds = curr->ds; } - Object_pool::Guard info(_ds_registry.lookup_info(ds_cap)); - if (!info) { - PERR("attempt to write to unknown dataspace type"); - for (;;); + if (!ds.valid()) { + PERR("replay: Error while forking dataspace"); + continue; + } + + Rm_session_client(dst_rm).attach(ds, curr->size, + curr->offset, + true, + curr->local_addr); + } + } + + void poke(addr_t dst_addr, void const *src, size_t len) + { + Dataspace_capability ds_cap; + addr_t local_addr; + + { + Lock::Guard guard(_region_lock); + + Region *region = _lookup_region_by_addr(dst_addr); + if (!region) { + PERR("poke: no region at 0x%lx", dst_addr); return; } - info->poke(dst_addr - local_addr, src, len); - } - - - /************************** - ** RM session interface ** - **************************/ - - Local_addr attach(Dataspace_capability ds, - size_t size = 0, off_t offset = 0, - bool use_local_addr = false, - Local_addr local_addr = (addr_t)0, - bool executable = false) - { /* - * Rm_session subtracts offset from size if size is 0 + * Test if start and end address occupied by the object + * type refers to the same region. */ - if (size == 0) - size = Dataspace_client(ds).size() - offset; - - local_addr = _rm.attach(ds, size, offset, - use_local_addr, local_addr, - executable); - - Region *region = new (env()->heap()) - Region(*this, ds, size, offset, local_addr); - - /* register region as user of RAM dataspaces */ - { - Object_pool::Guard info(_ds_registry.lookup_info(ds)); - - if (info) { - info->register_user(*region); - } else { - if (verbose_attach) { - PWRN("Trying to attach unknown dataspace type"); - PWRN(" ds_info@%p at 0x%lx size=%zd offset=0x%lx", - info.object(), (long)local_addr, - Dataspace_client(ds).size(), (long)offset); - } - } + if (region != _lookup_region_by_addr(dst_addr + len - 1)) { + PERR("attempt to write beyond region boundary"); + return; } - /* - * Record attachment for later replay (needed during - * fork) - */ + if (region->offset) { + PERR("poke: writing to region with offset is not supported"); + return; + } + + ds_cap = region->ds; + local_addr = region->local_addr; + } + + Object_pool::Guard info(_ds_registry.lookup_info(ds_cap)); + if (!info) { + PERR("attempt to write to unknown dataspace type"); + for (;;); + return; + } + + info->poke(dst_addr - local_addr, src, len); + } + + + /************************** + ** RM session interface ** + **************************/ + + Local_addr attach(Dataspace_capability ds, + size_t size = 0, off_t offset = 0, + bool use_local_addr = false, + Local_addr local_addr = (addr_t)0, + bool executable = false) + { + /* + * Rm_session subtracts offset from size if size is 0 + */ + if (size == 0) size = Dataspace_client(ds).size() - offset; + + local_addr = _rm.attach(ds, size, offset, use_local_addr, + local_addr, executable); + + Region * region = new (env()->heap()) + Region(*this, ds, size, offset, local_addr); + + /* register region as user of RAM dataspaces */ + { + Object_pool::Guard info(_ds_registry.lookup_info(ds)); + + if (info) { + info->register_user(*region); + } else { + if (verbose_attach) { + PWRN("Trying to attach unknown dataspace type"); + PWRN(" ds_info@%p at 0x%lx size=%zd offset=0x%lx", + info.object(), (long)local_addr, + Dataspace_client(ds).size(), (long)offset); + } + } + } + + /* + * Record attachment for later replay (needed during + * fork) + */ + Lock::Guard guard(_region_lock); + _regions.insert(region); + + return local_addr; + } + + void detach(Local_addr local_addr) + { + Region * region = 0; + { Lock::Guard guard(_region_lock); - _regions.insert(region); - - - return local_addr; - } - - void detach(Local_addr local_addr) - { - Region * region = 0; - { - Lock::Guard guard(_region_lock); - region = _lookup_region_by_addr(local_addr); - if (!region) { - PWRN("Attempt to detach unknown region at 0x%p", - (void *)local_addr); - return; - } - - _regions.remove(region); + region = _lookup_region_by_addr(local_addr); + if (!region) { + PWRN("Attempt to detach unknown region at 0x%p", + (void *)local_addr); + return; } - { - Object_pool::Guard info(_ds_registry.lookup_info(region->ds)); - if (info) - info->unregister_user(*region); - } - - destroy(env()->heap(), region); - - _rm.detach(local_addr); - + _regions.remove(region); } - Pager_capability add_client(Thread_capability thread) { - return _rm.add_client(thread); + Object_pool::Guard info(_ds_registry.lookup_info(region->ds)); + if (info) info->unregister_user(*region); } - void remove_client(Pager_capability pager) - { - _rm.remove_client(pager); - } + destroy(env()->heap(), region); - void fault_handler(Signal_context_capability handler) - { - return _rm.fault_handler(handler); - } + _rm.detach(local_addr); - State state() - { - return _rm.state(); - } + } - Dataspace_capability dataspace() - { - return _rm.dataspace(); - } - }; + Pager_capability add_client(Thread_capability thread) + { + return _rm.add_client(thread); + } + + void remove_client(Pager_capability pager) + { + _rm.remove_client(pager); + } + + void fault_handler(Signal_context_capability handler) + { + return _rm.fault_handler(handler); + } + + State state() + { + return _rm.state(); + } + + Dataspace_capability dataspace() + { + return _rm.dataspace(); + } +}; - inline void Rm_session_component::Region::dissolve(Dataspace_info &ds) - { - rm.detach(local_addr); - } +inline void Noux::Rm_session_component::Region::dissolve(Dataspace_info &ds) +{ + rm.detach(local_addr); } + #endif /* _NOUX__RM_SESSION_COMPONENT_H_ */