/* * \brief RAM service used by Noux processes * \author Norman Feske * \date 2012-02-22 * * The custom implementation of the RAM session interface provides a pool of * RAM shared by Noux and all Noux processes. The use of a shared pool * alleviates the need to assign RAM quota to individual Noux processes. * * Furthermore, the custom implementation is needed to get hold of the RAM * dataspaces allocated by each Noux process. When forking a process, the * acquired information (in the form of 'Ram_dataspace_info' objects) is used * to create a shadow copy of the forking address space. */ /* * Copyright (C) 2012-2013 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. */ #ifndef _NOUX__RAM_SESSION_COMPONENT_H_ #define _NOUX__RAM_SESSION_COMPONENT_H_ /* Genode includes */ #include #include #include /* Noux includes */ #include namespace Noux { struct Ram_dataspace_info : Dataspace_info, List::Element { Ram_dataspace_info(Ram_dataspace_capability ds_cap) : Dataspace_info(ds_cap) { } Dataspace_capability fork(Ram_session_capability ram, Dataspace_registry &, Rpc_entrypoint &) { size_t const size = Dataspace_client(ds_cap()).size(); Ram_dataspace_capability dst_ds; try { dst_ds = Ram_session_client(ram).alloc(size); } catch (...) { return Dataspace_capability(); } void *src = 0; try { src = env()->rm_session()->attach(ds_cap()); } catch (...) { } void *dst = 0; try { dst = env()->rm_session()->attach(dst_ds); } catch (...) { } if (src && dst) memcpy(dst, src, size); if (src) env()->rm_session()->detach(src); if (dst) env()->rm_session()->detach(dst); if (!src || !dst) { Ram_session_client(ram).free(dst_ds); return Dataspace_capability(); } return dst_ds; } void poke(addr_t dst_offset, void const *src, size_t len) { if ((dst_offset >= size()) || (dst_offset + len > size())) { PERR("illegal attemt to write beyond dataspace boundary"); return; } char *dst = 0; try { dst = env()->rm_session()->attach(ds_cap()); } catch (...) { } if (src && dst) memcpy(dst + dst_offset, src, len); if (dst) env()->rm_session()->detach(dst); } }; class Ram_session_component : public Rpc_object { private: List _list; /* * Track the RAM resources accumulated via RAM session allocations. * * XXX not used yet */ size_t _used_quota; Dataspace_registry &_registry; public: /** * Constructor */ Ram_session_component(Dataspace_registry ®istry) : _used_quota(0), _registry(registry) { } /** * Destructor */ ~Ram_session_component() { Ram_dataspace_info *info = 0; while ((info = _list.first())) free(static_cap_cast(info->ds_cap())); } /*************************** ** Ram_session interface ** ***************************/ Ram_dataspace_capability alloc(size_t size, bool cached) { Ram_dataspace_capability ds_cap = env()->ram_session()->alloc(size, cached); Ram_dataspace_info *ds_info = new (env()->heap()) Ram_dataspace_info(ds_cap); _used_quota += ds_info->size(); _registry.insert(ds_info); _list.insert(ds_info); return ds_cap; } void free(Ram_dataspace_capability ds_cap) { Ram_dataspace_info *ds_info = dynamic_cast(_registry.lookup_info(ds_cap)); if (!ds_info) { PERR("RAM free: dataspace lookup failed"); return; } ds_info->dissolve_users(); _registry.remove(ds_info); _list.remove(ds_info); _used_quota -= ds_info->size(); env()->ram_session()->free(ds_cap); destroy(env()->heap(), ds_info); } int ref_account(Ram_session_capability) { return 0; } int transfer_quota(Ram_session_capability, size_t) { return 0; } size_t quota() { return env()->ram_session()->quota(); } size_t used() { return _used_quota; } }; } #endif /* _NOUX__RAM_SESSION_COMPONENT_H_ */