Files
foc/l4/pkg/l4sys/include/capability
2013-01-11 17:00:47 +01:00

568 lines
15 KiB
C++

// vim:set ft=cpp:
/**
* \file
* \brief L4::Capability class.
*
* \author Alexander Warg <alexander.warg@os.inf.tu-dresden.de>
*
*/
/*
* (c) 2008-2009 Author(s)
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
#pragma once
#include <l4/sys/consts.h>
#include <l4/sys/types.h>
#include <l4/sys/kernel_object.h>
#include <l4/sys/task.h>
#include <l4/sys/__typeinfo.h>
namespace L4
{
/* Forward declarations for our kernel object classes. */
class Task;
class Thread;
class Factory;
class Irq;
class Log;
class Vm;
class Kobject;
template< typename T > class Cap;
/**
* \addtogroup l4_cap_api
*
* C++ interface for capabilities:<br>
* <c>\#include <l4/sys/capability></c>
*/
/*@{*/
/**
* \brief Base class for all kinds of capabilities.
* \attention This class is not for direct use, use L4::Cap instead.
*
* This class contains all the things that are independent of the type
* of the object referred by the capability.
*
* \see L4::Cap for typed capabilities.
*/
class Cap_base
{
private:
struct Invalid_conversion;
public:
enum No_init_type
{
/**
* \brief Special value for constructing uninitialized Cap objects.
*/
No_init
};
/**
* \brief Invalid capability type.
*/
enum Cap_type
{
Invalid = L4_INVALID_CAP ///< Invalid capability selector
};
/**
* \brief Return capability selector.
* \return Capability selector.
*/
l4_cap_idx_t cap() const throw() { return _c; }
/**
* \brief Test whether capability selector is not the invalid capability
* selector.
*
* \return True if capability is not invalid, false if invalid
*/
bool is_valid() const throw() { return !(_c & L4_INVALID_CAP_BIT); }
operator Invalid_conversion * () const throw()
{ return (Invalid_conversion*)(!(_c & L4_INVALID_CAP_BIT)); }
/**
* \brief Returns flex-page of the capability selector.
* \param rights Rights, defaults to 'rwx'
* \return flex-page
*/
l4_fpage_t fpage(unsigned rights = L4_FPAGE_RWX) const throw()
{ return l4_obj_fpage(_c, 0, rights); }
/**
* \brief Returns send base.
* \param grant True object should be granted.
* \param base Base capability selector
* \return Map object.
*/
l4_umword_t snd_base(unsigned grant = 0,
l4_cap_idx_t base = L4_INVALID_CAP) const throw()
{
if (base == L4_INVALID_CAP)
base = _c;
return l4_map_obj_control(base, grant);
}
/**
* \brief Test if two capability selectors are equal.
*/
bool operator == (Cap_base const &o) const throw()
{ return _c == o._c; }
/**
* \brief Test if two capability selectors are not equal.
*/
bool operator != (Cap_base const &o) const throw()
{ return _c != o._c; }
/**
* \brief Check whether a capability selector points to a valid capability.
*
* \param u UTCB of the caller
* \return label = 0 valid, label > 0 invalid
*/
inline l4_msgtag_t validate(l4_utcb_t *u = l4_utcb()) const throw();
/**
* \brief Check whether a capability selector points to a valid capability.
*
* \param u UTCB of the caller
* \param task Task to check the capability in
*
* \return label = 0 valid, label > 0 invalid
*/
inline l4_msgtag_t validate(Cap<Task> task,
l4_utcb_t *u = l4_utcb()) const throw();
/**
* \brief Set this selector to the invalid capability (L4_INVALID_CAP).
*/
void invalidate() throw() { _c = L4_INVALID_CAP; }
protected:
/**
* \brief Generate a capability from its C representation.
* \param c the C capability selector
*/
explicit Cap_base(l4_cap_idx_t c) throw() : _c(c) {}
/**
* \brief Constructor to create an invalid capability selector.
*/
explicit Cap_base(Cap_type cap) throw() : _c(cap) {}
/**
* \brief Initialize capability with one of the default capability selectors.
* \param cap Capability selector.
*/
explicit Cap_base(l4_default_caps_t cap) throw() : _c(cap) {}
/**
* \brief Create an uninitialized instance.
*/
explicit Cap_base() throw() {}
/**
* \brief The C representation of a capability selector. */
l4_cap_idx_t _c;
};
/**
* \brief Capability Selector a la C++.
* \tparam T the type of the object the capability points to
*
* The C++ version of a capability looks just as a pointer, in fact
* it is a kind of a smart pointer for our kernel objects and the
* objects derived from the kernel objects (L4::Kobject).
*/
template< typename T >
class Cap : public Cap_base
{
private:
friend class L4::Kobject;
/**
* \internal
* \brief Internal Constructor, use to generate a capability from a \a this
* pointer.
*
* \attention This constructor is only useful to generate a capability
* from the \a this pointer of an objected that is an L4::Kobject.
* Do \em never use this constructor for something else!
* \param p The \a this pointer of the Kobject or derived object
*/
explicit Cap(T const *p) throw()
: Cap_base(reinterpret_cast<l4_cap_idx_t>(p)) {}
public:
/**
* \brief Create a copy from \a o, supporting implicit type casting.
* \param o is the source selector that shall be copied (and casted).
*/
template< typename O >
Cap(Cap<O> const &o) throw() : Cap_base(o.cap())
{ register T* __t = ((O*)100); (void)__t; }
/**
* \brief Constructor to create an invalid capability selector.
*/
Cap(Cap_type cap) throw() : Cap_base(cap) {}
/**
* \brief Initialize capability with one of the default capability selectors.
* \param cap Capability selector.
*/
Cap(l4_default_caps_t cap) throw() : Cap_base(cap) {}
/**
* \brief Initialize capability, defaults to the invalid capability selector.
* \param idx Capability selector.
*/
explicit Cap(l4_cap_idx_t idx = L4_INVALID_CAP) throw() : Cap_base(idx) {}
/**
* \brief Create an uninitialized cap selector.
*/
explicit Cap(No_init_type) throw() {}
/**
* \brief Move a capability to this cap slot.
* \param src the source capability slot.
*
* After this operation the source slot is no longer valid.
*/
Cap move(Cap const &src) const
{
if (!is_valid() || !src.is_valid())
return *this;
l4_task_map(L4_BASE_TASK_CAP, L4_BASE_TASK_CAP, src.fpage(L4_FPAGE_RWX),
snd_base(L4_MAP_ITEM_GRANT));
return *this;
}
/**
* \brief Member access of a \a T.
*/
T *operator -> () const throw() { return reinterpret_cast<T*>(_c); }
};
/**
* \internal
* \brief Specialization for \a void capabilities.
*/
template<>
class Cap<void> : public Cap_base
{
public:
explicit Cap(void const *p) throw()
: Cap_base(reinterpret_cast<l4_cap_idx_t>(p)) {}
/**
* \brief Constructor to create an invalid capability selector.
*/
Cap(Cap_type cap) throw() : Cap_base(cap) {}
/**
* \brief Initialize capability with one of the default capability selectors.
* \param cap Capability selector.
*/
Cap(l4_default_caps_t cap) throw() : Cap_base(cap) {}
/**
* \brief Initialize capability, defaults to the invalid capability selector.
* \param idx Capability selector.
*/
explicit Cap(l4_cap_idx_t idx = L4_INVALID_CAP) throw() : Cap_base(idx) {}
explicit Cap(No_init_type) throw() {}
/**
* \brief Move a capability to this cap slot.
* \param src the source capability slot.
*
* After this operation the source slot is no longer valid.
*/
Cap move(Cap const &src) const
{
if (!is_valid() || !src.is_valid())
return *this;
l4_task_map(L4_BASE_TASK_CAP, L4_BASE_TASK_CAP, src.fpage(L4_FPAGE_RWX),
snd_base(L4_MAP_ITEM_GRANT));
return *this;
}
template< typename T >
Cap(Cap<T> const &o) throw() : Cap_base(o.cap()) {}
};
/**
* \brief static_cast for capabilities.
* \param T is the target type of the capability
* \param F is the source type (and is usually implicitly set)
* \param c is the source capability that shall be casted
* \return A capability typed to the interface \a T.
*
* The use of this cast operator is similar to the static_cast<>() for
* C++ pointers. It does the same type checking and adjustment like
* C++ does on pointers.
*
* Example code:
* \code
* L4::Cap<L4::Kobject> obj = ... ;
* L4::Cap<L4::Icu> icu = L4::cap_cast<L4::Icu>(obj);
* \endcode
*/
template< typename T, typename F >
inline
Cap<T> cap_cast(Cap<F> const &c) throw()
{
(void)static_cast<T const *>(reinterpret_cast<F const *>(100));
return Cap<T>(c.cap());
}
/**
* \brief reinterpret_cast for capabilities.
* \param T is the target type of the capability
* \param F is the source type (and is usually implicitly set)
* \param c is the source capability that shall be casted
* \return A capability typed to the interface \a T.
*
* The use of this cast operator is similar to the reinterpret_cast<>() for
* C++ pointers. It does not do any type checking or type adjustment.
*
* Example code:
* \code
* L4::Cap<L4::Kobject> obj = ... ;
* L4::Cap<L4::Icu> icu = L4::cap_reinterpret_cast<L4::Icu>(obj);
* \endcode
*/
template< typename T, typename F >
inline
Cap<T> cap_reinterpret_cast(Cap<F> const &c) throw()
{
return Cap<T>(c.cap());
}
/*@}*/
/**
* \addtogroup l4_kernel_object_api
*
* <c>\#include <l4/sys/capability></c>
*/
/*@{*/
/**
* \brief Disable copy of a class.
* \param _class is the name of the class that shall not have
* value copy semantics.
*
*
* The typical use of this is:
* \code
* class Non_value
* {
* L4_DISABLE_COPY(Non_value)
*
* ...
* }
* \endcode
*/
#define L4_DISABLE_COPY(_class) \
private: \
_class(_class const &); \
_class operator = (_class const &);
/**
* \brief Disable copy and instantiation of a class.
* \param _class is the name of the class to be not copyable and not
* instantiatable.
*
* The typical use looks like:
* \code
* class Type
* {
* L4_KOBJECT_DISABLE_COPY(Type)
* };
* \endcode
*/
#define L4_KOBJECT_DISABLE_COPY(_class) \
protected: \
_class(); \
L4_DISABLE_COPY(_class)
/**
* \brief Declare a kernel object class.
* \param _class is the class name.
*
* The use of this macro disables copy and instantiation
* of the class as needed for kernel object classes derived from
* L4::Kobject.
*
* The typical use looks like:
* \code
* class Type : public L4::Kobject_t<Type, L4::Kobject>
* {
* L4_KOBJECT(Type)
* };
* \endcode
*/
#define L4_KOBJECT(_class) L4_KOBJECT_DISABLE_COPY(_class)
/**
* \ingroup l4_kernel_object_api
* \brief Base class for all kinds of kernel objects, referred to by
* capabilities.
*
* <c>\#include <l4/sys/capability></c>
*
* \attention Objects derived from Kobject \em must never add any data to
* those objects. Kobjects can act only as proxy object
* for encapsulating object invocations.
*/
class Kobject
{
L4_KOBJECT(Kobject)
private:
template<typename T>
friend Type_info const *kobject_typeid();
protected:
/**
* \internal
* \brief Get a pointer to the L4Re dynamic type information
* for this class.
*
* \note This function is used by L4::kobject_typeid().
*/
struct __Kobject_typeid { static Type_info const _m; };
/**
* \brief Return capability selector.
* \return Capability selector.
*
* This method is for derived classes to gain access to the actual
* capability selector.
*/
l4_cap_idx_t cap() const throw() { return _c(); }
private:
/**
* \internal
* \brief Used to convert the \c this pointer to a capability selector.
*/
l4_cap_idx_t _c() const throw()
{ return reinterpret_cast<l4_cap_idx_t>(this) & L4_CAP_MASK; }
public:
/**
* \brief Decrement the in kernel reference counter for the object.
* \param diff is the delta that shall be subtracted from the reference
* count.
* \param utcb is the utcb to use for the invocation.
*
* This function is intended for servers to be able to remove the servers
* own capability from the counted references. This leads to the semantics
* that the kernel will delete the object even if the capability of the
* server is valid. The server can detect the deletion by polling its
* capabilities or by using the IPC-gate deletion IRQs. And to cleanup
* if the clients dropped the last reference (capability) to the object.
*/
l4_msgtag_t dec_refcnt(l4_mword_t diff, l4_utcb_t *utcb = l4_utcb())
{ return l4_kobject_dec_refcnt_u(cap(), diff, utcb); }
};
/*@}*/
inline l4_msgtag_t
Cap_base::validate(Cap<Task> task, l4_utcb_t *u) const throw()
{ return l4_task_cap_valid_u(task.cap(), _c, u); }
inline l4_msgtag_t
Cap_base::validate(l4_utcb_t *u) const throw()
{ return l4_task_cap_valid_u(L4_BASE_TASK_CAP, _c, u); }
}; // namespace L4
#include <l4/sys/meta>
namespace L4 {
/**
* \addtogroup l4_cap_api
*/
/*@{*/
/**
* \brief dynamic_cast for capabilities.
* \param T is the target type of the capability
* \param F is the source type (and is usually implicitly set)
* \param c is the source capability that shall be casted
* \return A capability typed to the interface \a T. If the object does not
* support the target interface \a T or does not support the
* L4::Meta interface the result is the invalid capability selector.
*
* The use of this cast operator is similar to the dynamic_cast<>() for
* C++ pointers. It also induces overhead, because it uses the meta interface
* (L4::Meta) to do runtime type checking.
*
* Example code:
* \code
* L4::Cap<L4::Kobject> obj = ... ;
* L4::Cap<L4::Icu> icu = L4::cap_dynamic_cast<L4::Icu>(obj);
* \endcode
*/
template< typename T, typename F >
inline
Cap<T> cap_dynamic_cast(Cap<F> const &c) throw()
{
if (!c.is_valid())
return Cap<T>::Invalid;
Cap<Meta> mc = cap_reinterpret_cast<Meta>(c);
Type_info const *m = kobject_typeid<T>();
if (m->proto() && l4_error(mc->supports(m->proto())) > 0)
return Cap<T>(c.cap());
// FIXME: use generic checker
#if 0
if (l4_error(mc->supports(T::kobject_proto())) > 0)
return Cap<T>(c.cap());
#endif
return Cap<T>::Invalid;
}
/*@}*/
}