genode/repos/base-sel4/src/base/internal/capability_space_sel4.h

272 lines
6.2 KiB
C++

/*
* \brief seL4-specific capability-space management
* \author Norman Feske
* \date 2015-05-08
*/
/*
* Copyright (C) 2015 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 _BASE__INTERNAL__CAPABILITY_SPACE_SEL4_H_
#define _BASE__INTERNAL__CAPABILITY_SPACE_SEL4_H_
/* base includes */
#include <util/avl_tree.h>
#include <base/lock.h>
/* base-internal includes */
#include <internal/capability_space.h>
#include <internal/assert.h>
namespace Genode {
template <unsigned, unsigned, typename> class Capability_space_sel4;
class Cap_sel
{
private:
addr_t _value;
public:
explicit Cap_sel(addr_t value) : _value(value) { }
addr_t value() const { return _value; }
};
}
/**
* Platform-specific supplement to the generic 'Capability_space' interface
*/
namespace Genode { namespace Capability_space {
/**
* Information needed to transfer capability via the kernel's IPC mechanism
*/
struct Ipc_cap_data
{
Rpc_obj_key rpc_obj_key;
Cap_sel sel;
Ipc_cap_data(Rpc_obj_key rpc_obj_key, unsigned sel)
: rpc_obj_key(rpc_obj_key), sel(sel) { }
};
/**
* Retrieve IPC data for given capability
*/
Ipc_cap_data ipc_cap_data(Native_capability const &cap);
/**
* Allocate unused selector for receiving a capability via IPC
*/
unsigned alloc_rcv_sel();
/**
* Delete selector but retain allocation
*
* This function is used when a delegated capability selector is replaced
* with an already known selector. The delegated selector is discarded.
*/
void reset_sel(unsigned sel);
/**
* Lookup capability by its RPC object key
*/
Native_capability lookup(Rpc_obj_key key);
/**
* Import capability into the component's capability space
*/
Native_capability import(Ipc_cap_data ipc_cap_data);
} }
namespace Genode
{
enum {
INITIAL_SEL_PARENT = 1,
INITIAL_SEL_CNODE = 2,
INITIAL_SEL_END
};
enum {
CSPACE_SIZE_LOG2 = 8,
NUM_CORE_MANAGED_SEL_LOG2 = 7,
};
};
/**
* Capability space template
*
* The capability space of core and non-core components differ in two ways.
*
* First, core must keep track of all capabilities of the system. Hence, its
* capability space must be dimensioned larger.
*
* Second, core has to maintain the information about the CAP session that
* was used to allocate the capability to prevent misbehaving clients from
* freeing capabilities allocated from another component. This information
* is part of the core-specific 'Native_capability::Data' structure.
*/
template <unsigned NUM_CAPS, unsigned _NUM_CORE_MANAGED_CAPS, typename CAP_DATA>
class Genode::Capability_space_sel4
{
public:
/*
* The capability space consists of two parts. The lower part is
* populated with statically-defined capabilities whereas the upper
* part is dynamically managed by the component. The
* 'NUM_CORE_MANAGED_CAPS' defines the size of the first part.
*/
enum { NUM_CORE_MANAGED_CAPS = _NUM_CORE_MANAGED_CAPS };
private:
typedef CAP_DATA Data;
/**
* Supplement Native_capability::Data with the meta data needed to
* manage it in an AVL tree
*/
struct Tree_managed_data : Data, Avl_node<Tree_managed_data>
{
template <typename... ARGS>
Tree_managed_data(ARGS... args) : Data(args...) { }
Tree_managed_data() { }
bool higher(Tree_managed_data *data)
{
return data->rpc_obj_key().value() > rpc_obj_key().value();
}
Tree_managed_data *find_by_key(Rpc_obj_key key)
{
if (key.value() == rpc_obj_key().value()) return this;
Tree_managed_data *data =
this->child(key.value() > rpc_obj_key().value());
return data ? data->find_by_key(key) : nullptr;
}
};
Tree_managed_data _caps_data[NUM_CAPS];
Avl_tree<Tree_managed_data> _tree;
Lock mutable _lock;
/**
* Calculate index into _caps_data for capability data object
*/
unsigned _index(Data const &data) const
{
addr_t const offset = (addr_t)&data - (addr_t)_caps_data;
return offset / sizeof(_caps_data[0]);
}
/**
* Return true if capability is locally managed by the component
*/
bool _is_core_managed(Data &data) const
{
return _index(data) < NUM_CORE_MANAGED_CAPS;
}
void _remove(Native_capability::Data &data)
{
if (_caps_data[_index(data)].rpc_obj_key().valid())
_tree.remove(static_cast<Tree_managed_data *>(&data));
_caps_data[_index(data)] = Tree_managed_data();
}
public:
/*****************************************************
** Support for the Core_capability_space interface **
*****************************************************/
/**
* Create Genode capability for kernel cap selector 'sel'
*
* The arguments following the selector are passed to the constructor
* of the 'Native_capability::Data' type.
*/
template <typename... ARGS>
Native_capability::Data &create_capability(Cap_sel cap_sel, ARGS... args)
{
Lock::Guard guard(_lock);
addr_t const sel = cap_sel.value();
ASSERT(!_caps_data[sel].rpc_obj_key().valid());
ASSERT(sel < NUM_CAPS);
_caps_data[sel] = Tree_managed_data(args...);
if (_caps_data[sel].rpc_obj_key().valid())
_tree.insert(&_caps_data[sel]);
return _caps_data[sel];
}
/**
* Return kernel cap selector
*/
unsigned sel(Data const &data) const { return _index(data); }
/************************************************
** Support for the Capability_space interface **
************************************************/
void dec_ref(Data &data)
{
Lock::Guard guard(_lock);
if (!_is_core_managed(data) && !data.dec_ref())
_remove(data);
}
void inc_ref(Data &data)
{
Lock::Guard guard(_lock);
if (!_is_core_managed(data)) {
data.inc_ref();
}
}
Rpc_obj_key rpc_obj_key(Data const &data) const
{
return data.rpc_obj_key();
}
Capability_space::Ipc_cap_data ipc_cap_data(Data const &data) const
{
return { rpc_obj_key(data), sel(data) };
}
Data *lookup(Rpc_obj_key key) const
{
Lock::Guard guard(_lock);
if (!_tree.first())
return nullptr;
return _tree.first()->find_by_key(key);
}
};
#endif /* _BASE__INTERNAL__CAPABILITY_SPACE_SEL4_H_ */