From f330b5522735bff296ba39968177339fc7486189 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Mon, 26 Aug 2013 12:42:12 +0200 Subject: [PATCH] nova: introduce cap_map to be used for ref counting of Native_capabilities * similar as used for base-foc * will replace nova specific cap_sel_allocator interface Issue #905 --- base-nova/include/base/cap_map.h | 129 ++++++++++++++++++++++++ base-nova/lib/mk/base-common.inc | 1 + base-nova/src/base/env/cap_map.cc | 157 ++++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 base-nova/include/base/cap_map.h create mode 100644 base-nova/src/base/env/cap_map.cc diff --git a/base-nova/include/base/cap_map.h b/base-nova/include/base/cap_map.h new file mode 100644 index 000000000..9493b6d30 --- /dev/null +++ b/base-nova/include/base/cap_map.h @@ -0,0 +1,129 @@ +/* + * \brief Mapping of Genode's capability names to capabilities selectors. + * \author Alexander Boettcher + * \date 2013-08-26 + * + */ + +/* + * Copyright (C) 2013-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 _INCLUDE__BASE__CAP_MAP_H_ +#define _INCLUDE__BASE__CAP_MAP_H_ + +/* Genode includes */ +#include + +#include + +#include +#include + +namespace Genode { + + class Cap_range : public Avl_node { + + private: + + Lock _lock; + addr_t _base; + addr_t _last; + + enum { + HEADER = sizeof(_base) + sizeof(_lock) + sizeof(_last), + CAP_RANGE_SIZE = 4096, + WORDS = (CAP_RANGE_SIZE - HEADER - sizeof(Avl_node)) / sizeof(addr_t), + }; + + uint8_t _cap_array[WORDS * sizeof(addr_t)]; + + bool _match(addr_t id) { + return _base <= id && id < _base + sizeof(_cap_array); }; + + public: + + Cap_range(addr_t base) : _base(base), _last(0) { + + static_assert(sizeof(*this) == CAP_RANGE_SIZE, + "Cap_range misconfigured"); + + for (unsigned i=0; i < sizeof(_cap_array); i++) + _cap_array[i] = 0; + } + + addr_t const base() const { return _base; } + unsigned const elements() { return sizeof(_cap_array); } + + Cap_range *find_by_id(addr_t); + + void inc(unsigned id, bool inc_if_one = false); + void dec(unsigned id, bool revoke = true); + + addr_t alloc(size_t const num_log2); + + /************************ + ** Avl node interface ** + ************************/ + + bool higher(Cap_range *n) { return n->_base > _base; } + + }; + + + class Cap_index + { + private: + + Cap_range * _range; + addr_t _local_name; + + public: + + Cap_index(Cap_range *range, addr_t local_name) + : _range(range), _local_name(local_name) {} + + bool valid() const { return _range; } + + inline void inc(bool inc_if_one = false) + { + if (_range) + _range->inc(_local_name - _range->base(), inc_if_one); + } + + inline void dec() + { + if (_range) + _range->dec(_local_name - _range->base()); + } + }; + + + class Capability_map : Noncopyable + { + private: + + Avl_tree _tree; + + public: + + Cap_index find(addr_t local_sel); + + void insert(Cap_range * range) { _tree.insert(range); } + + addr_t insert(size_t num_log_2 = 0, addr_t cap = ~0UL); + + void remove(addr_t sel, uint8_t num_log_2 = 0, bool revoke = true); + }; + + + /** + * Get the global Capability_map of the process. + */ + Capability_map *cap_map(); +} + +#endif /* _INCLUDE__BASE__CAP_MAP_H_ */ diff --git a/base-nova/lib/mk/base-common.inc b/base-nova/lib/mk/base-common.inc index 94e8c0b6e..99f94cfec 100644 --- a/base-nova/lib/mk/base-common.inc +++ b/base-nova/lib/mk/base-common.inc @@ -20,6 +20,7 @@ SRC_CC += lock/lock.cc SRC_CC += signal/signal.cc signal/common.cc SRC_CC += server/server.cc SRC_CC += thread/thread.cc thread/thread_context.cc thread/trace.cc +SRC_CC += env/cap_map.cc INC_DIR += $(REP_DIR)/src/base/lock INC_DIR += $(BASE_DIR)/src/base/lock diff --git a/base-nova/src/base/env/cap_map.cc b/base-nova/src/base/env/cap_map.cc new file mode 100644 index 000000000..524f6e8a0 --- /dev/null +++ b/base-nova/src/base/env/cap_map.cc @@ -0,0 +1,157 @@ +/* + * \brief Mapping of Genode's capability names to kernel capabilities. + * \author Alexander Boettcher + * \date 2013-08-26 + */ + +/* + * Copyright (C) 2013-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. + */ + +#include + +/* base-nova specific include */ +#include + +using namespace Genode; + + +Capability_map *Genode::cap_map() { + static Genode::Capability_map map; + return ↦ +} + + +/*********************** + ** Cap_index class ** + ***********************/ + + +Cap_range *Cap_range::find_by_id(addr_t id) +{ + if (_match(id)) return this; + + Cap_range *obj = this->child(id > _base); + return obj ? obj->find_by_id(id) : 0; +} + + +void Cap_range::inc(unsigned id, bool inc_if_one) { + + Lock::Guard guard(_lock); + + if (inc_if_one && _cap_array[id] != 1) + return; + + if (_cap_array[id] == 255) { +// PERR("cap overflow - selector %lx - return address %p", +// _base + id, __builtin_return_address(0)); + *reinterpret_cast(0) = 0xdead; + } + + _cap_array[id]++; +} + + +void Cap_range::dec(unsigned id, bool revoke) { + + Lock::Guard guard(_lock); + + if (_cap_array[id] == 0) + *reinterpret_cast(0) = 0xdead; + + if (revoke && _cap_array[id] == 1) + Nova::revoke(Nova::Obj_crd(_base + id, 0)); + + _cap_array[id]--; +} + + +addr_t Cap_range::alloc(size_t const num_log2) +{ + addr_t const step = 1UL << num_log2; + + { + Lock::Guard guard(_lock); + + unsigned max = elements(); + addr_t last = _last; + + do { + + /* align i to num_log2 */ + unsigned i = ((_base + last + step - 1) & ~(step - 1)) - _base; + unsigned j; + for (; i + step < max; i += step) { + for (j = 0; j < step; j++) + if (_cap_array[i+j]) + break; + if (j < step) + continue; + + for (j = 0; j < step; j++) + _cap_array[i+j] = 1; + + _last = i; + return _base + i; + } + + max = last; + last = 0; + + } while (max); + } + + Cap_range *child = this->child(LEFT); + if (child) { + addr_t res = child->alloc(num_log2); + if (res != ~0UL) + return res; + } + child = this->child(RIGHT); + if (child) { + addr_t res = child->alloc(num_log2); + return res; + } + + return ~0UL; +} + + +/**************************** + ** Capability_map class ** + ****************************/ + + +Cap_index Capability_map::find(Genode::addr_t id) { + return Cap_index(_tree.first() ? _tree.first()->find_by_id(id) : 0, id); } + + +addr_t Capability_map::insert(size_t const num_log_2, addr_t const sel) +{ + if (sel == ~0UL) + return _tree.first() ? _tree.first()->alloc(num_log_2) : ~0UL; + + Cap_range * range = _tree.first() ? _tree.first()->find_by_id(sel) : 0; + if (!range) + return ~0UL; + + for (unsigned i = 0; i < 1UL << num_log_2; i++) + range->inc(sel + i - range->base()); + + return sel; +} + + +void Capability_map::remove(Genode::addr_t sel, uint8_t num_log_2, bool revoke) +{ + Cap_range * range = _tree.first() ? _tree.first()->find_by_id(sel) : 0; + if (!range) + return; + + for (unsigned i = 0; i < 1UL << num_log_2; i++) + range->dec(sel + i - range->base(), revoke); +}