/* * \brief Fiasco.OC-specific RPC capability factory * \author Stefan Kalkowski * \author Norman Feske * \date 2011-01-13 */ /* * Copyright (C) 2011-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ /* Genode includes */ #include #include /* core includes */ #include #include #include #include /* base-internal includes */ #include #include /* Fiasco includes */ namespace Fiasco { #include #include #include #include #include } using namespace Genode; /*************************** ** Cap_index_allocator ** ***************************/ Genode::Cap_index_allocator &Genode::cap_idx_alloc() { static Genode::Cap_index_allocator_tpl alloc; return alloc; } /******************* ** Cap_mapping ** *******************/ Core_cap_index *Cap_mapping::_get_cap() { int const id = platform_specific().cap_id_alloc().alloc(); return static_cast(cap_map().insert(id)); } void Cap_mapping::map(Fiasco::l4_cap_idx_t task) { using namespace Fiasco; if (!local.valid() || !Fiasco::Capability::valid(remote)) return; l4_msgtag_t tag = l4_task_map(task, L4_BASE_TASK_CAP, l4_obj_fpage(local.data()->kcap(), 0, L4_FPAGE_RWX), ((l4_cap_idx_t)remote) | L4_ITEM_MAP); if (l4_msgtag_has_error(tag)) error("mapping cap failed"); } Cap_mapping::Cap_mapping(bool alloc, Fiasco::l4_cap_idx_t r) : local(alloc ? _get_cap() : (Native_capability::Data *)nullptr), remote(r) { } Cap_mapping::Cap_mapping(Native_capability cap, Fiasco::l4_cap_idx_t r) : local(cap), remote(r) { } /*********************** ** Rpc_cap_factory ** ***********************/ Native_capability Rpc_cap_factory::alloc(Native_capability ep) { Native_capability cap; if (!ep.valid()) { warning("Invalid reference capability!"); return cap; } try { using namespace Fiasco; Core_cap_index const * ref = static_cast(ep.data()); ASSERT(ref && ref->pt(), "No valid platform_thread"); /* * Allocate new id, and ipc-gate and set id as gate-label */ unsigned long const id = platform_specific().cap_id_alloc().alloc(); Core_cap_index *idx = static_cast(cap_map().insert(id)); if (!idx) { warning("Out of capability indices!"); platform_specific().cap_id_alloc().free(id); return cap; } l4_msgtag_t tag = l4_factory_create_gate(L4_BASE_FACTORY_CAP, idx->kcap(), ref->pt()->thread().local.data()->kcap(), id); if (l4_msgtag_has_error(tag)) { error("l4_factory_create_gate failed!"); cap_map().remove(idx); platform_specific().cap_id_alloc().free(id); return cap; } else /* set debugger-name of ipc-gate to thread's name */ Fiasco::l4_debugger_set_object_name(idx->kcap(), ref->pt()->name().string()); // XXX remove cast idx->session((Pd_session_component *)this); idx->pt(ref->pt()); cap = Native_capability(idx); } catch (Cap_id_allocator::Out_of_ids) { error("out of capability IDs"); } /* * insert valid capabilities into the session's object pool to * be able to destroy them on session destruction. * For the construction of core's own threads the related cap session * doesn't have an allocator set. But this session gets never destroyed * so this is not an issue. */ if (cap.valid()) _pool.insert(new (_entry_slab) Entry(cap)); return cap; } void Rpc_cap_factory::free(Native_capability cap) { using namespace Fiasco; if (!cap.valid()) return; /* check whether the capability was created by this cap_session */ if (static_cast(cap.data())->session() != (Pd_session_component *)this) return; Entry * entry = nullptr; _pool.apply(cap, [&] (Entry *e) { entry = e; if (e) { _pool.remove(e); } else warning("Could not find capability to be deleted"); }); if (entry) destroy(_entry_slab, entry); } Rpc_cap_factory::~Rpc_cap_factory() { _pool.remove_all([this] (Entry *e) { if (!e) return; destroy(_entry_slab, e); }); } /******************************* ** Capability ID Allocator ** *******************************/ Cap_id_allocator::Cap_id_allocator(Allocator &alloc) : _id_alloc(&alloc) { _id_alloc.add_range(CAP_ID_OFFSET, CAP_ID_RANGE); } unsigned long Cap_id_allocator::alloc() { Lock::Guard lock_guard(_lock); void *id = nullptr; if (_id_alloc.alloc(CAP_ID_OFFSET, &id)) return (unsigned long) id; throw Out_of_ids(); } void Cap_id_allocator::free(unsigned long id) { Lock::Guard lock_guard(_lock); if (id < CAP_ID_RANGE) _id_alloc.free((void*)(id & CAP_ID_MASK), CAP_ID_OFFSET); } void Genode::Capability_map::remove(Genode::Cap_index *i) { using namespace Genode; using namespace Fiasco; Lock_guard guard(_lock); if (i) { Core_cap_index* e = static_cast(_tree.first() ? _tree.first()->find_by_id(i->id()) : 0); if (e == i) { l4_msgtag_t tag = l4_task_unmap(L4_BASE_TASK_CAP, l4_obj_fpage(i->kcap(), 0, L4_FPAGE_RWX), L4_FP_ALL_SPACES | L4_FP_DELETE_OBJ); if (l4_msgtag_has_error(tag)) error("destruction of ipc-gate ", i->kcap(), " failed!"); platform_specific().cap_id_alloc().free(i->id()); _tree.remove(i); } cap_idx_alloc().free(i, 1); } }