/* * \brief Mapping of Genode's capability names to kernel capabilities. * \author Stefan Kalkowski * \date 2010-12-06 * * This is a Fiasco.OC-specific addition to the process enviroment. */ /* * Copyright (C) 2010-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. */ /* base-internal includes */ #include #include #include /* kernel includes */ #include /** * We had to change the sematic of l4_task_cap_equal to return whether two * capabilities point to the same kernel object instead of whether both * capabilities are equal with respect to thier rights. To easily check after * a Fiasco.OC upgrade whether the sematic of the kernel patch still matches * our expectations below macro can be used. */ #ifdef TEST_KERN_CAP_EQUAL namespace Fiasco { #include } inline bool CHECK_CAP_EQUAL(bool equal, Genode::addr_t cap1, Genode::addr_t cap2) { unsigned long id1 = Fiasco::l4_debugger_global_id(cap1), id2 = Fiasco::l4_debugger_global_id(cap2); ASSERT(((id1 == id2) == equal), "CAPS NOT EQUAL!!!"); return equal; } #else inline bool CHECK_CAP_EQUAL(bool equal, Genode::addr_t, Genode::addr_t) { return equal; } #endif /* TEST_KERN_CAP_EQUAL */ /*********************** ** Cap_index class ** ***********************/ static volatile int _cap_index_spinlock = SPINLOCK_UNLOCKED; bool Genode::Cap_index::higher(Genode::Cap_index *n) { return n->_id > _id; } Genode::Cap_index* Genode::Cap_index::find_by_id(Genode::uint16_t id) { using namespace Genode; if (_id == id) return this; Cap_index *n = Avl_node::child(id > _id); return n ? n->find_by_id(id) : 0; } Genode::addr_t Genode::Cap_index::kcap() const { return cap_idx_alloc()->idx_to_kcap(this); } Genode::uint8_t Genode::Cap_index::inc() { /* con't ref-count index that are controlled by core */ if (cap_idx_alloc()->static_idx(this)) return 1; spinlock_lock(&_cap_index_spinlock); Genode::uint8_t ret = ++_ref_cnt; spinlock_unlock(&_cap_index_spinlock); return ret; } Genode::uint8_t Genode::Cap_index::dec() { /* con't ref-count index that are controlled by core */ if (cap_idx_alloc()->static_idx(this)) return 1; spinlock_lock(&_cap_index_spinlock); Genode::uint8_t ret = --_ref_cnt; spinlock_unlock(&_cap_index_spinlock); return ret; } /**************************** ** Capability_map class ** ****************************/ Genode::Cap_index* Genode::Capability_map::find(int id) { Genode::Lock_guard guard(_lock); return _tree.first() ? _tree.first()->find_by_id(id) : 0; } Genode::Cap_index* Genode::Capability_map::insert(int id) { using namespace Genode; Lock_guard guard(_lock); ASSERT(!_tree.first() || !_tree.first()->find_by_id(id), "Double insertion in cap_map()!"); Cap_index *i = cap_idx_alloc()->alloc_range(1); if (i) { i->id(id); _tree.insert(i); } return i; } Genode::Cap_index* Genode::Capability_map::insert(int id, addr_t kcap) { using namespace Genode; Lock_guard guard(_lock); /* remove potentially existent entry */ Cap_index *i = _tree.first() ? _tree.first()->find_by_id(id) : 0; if (i) _tree.remove(i); i = cap_idx_alloc()->alloc(kcap); if (i) { i->id(id); _tree.insert(i); } return i; } Genode::Cap_index* Genode::Capability_map::insert_map(int id, addr_t kcap) { using namespace Genode; using namespace Fiasco; Lock_guard guard(_lock); /* check whether capability id exists */ Cap_index *i = _tree.first() ? _tree.first()->find_by_id(id) : 0; /* if we own the capability already check whether it's the same */ if (i) { l4_msgtag_t tag = l4_task_cap_equal(L4_BASE_TASK_CAP, i->kcap(), kcap); if (!CHECK_CAP_EQUAL(l4_msgtag_label(tag), i->kcap(), kcap)) { /* * they aren't equal, possibly an already revoked cap, * otherwise it's a fake capability and we return an invalid one */ tag = l4_task_cap_valid(L4_BASE_TASK_CAP, i->kcap()); if (l4_msgtag_label(tag)) return 0; else /* it's invalid so remove it from the tree */ _tree.remove(i); } else /* they are equal so just return the one in the map */ return i; } /* the capability doesn't exists in the map so allocate a new one */ i = cap_idx_alloc()->alloc_range(1); if (!i) return 0; /* set it's id and insert it into the tree */ i->id(id); _tree.insert(i); /* map the given cap to our registry entry */ l4_task_map(L4_BASE_TASK_CAP, L4_BASE_TASK_CAP, l4_obj_fpage(kcap, 0, L4_FPAGE_RWX), i->kcap() | L4_ITEM_MAP | L4_MAP_ITEM_GRANT); return i; } Genode::Capability_map* Genode::cap_map() { static Genode::Capability_map map; return ↦ } /********************** ** Capability_space ** **********************/ Fiasco::l4_cap_idx_t Genode::Capability_space::alloc_kcap() { return cap_idx_alloc()->alloc_range(1)->kcap(); } void Genode::Capability_space::free_kcap(Fiasco::l4_cap_idx_t kcap) { Genode::Cap_index* idx = Genode::cap_idx_alloc()->kcap_to_idx(kcap); Genode::cap_idx_alloc()->free(idx, 1); } Fiasco::l4_cap_idx_t Genode::Capability_space::kcap(Native_capability cap) { if (cap.data() == nullptr) Genode::raw("Native_capability data is NULL!"); return cap.data()->kcap(); }