// vim:set ft=cpp: /** * \file * \brief L4::Capability class. * * \author Alexander Warg * */ /* * (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 #include #include #include #include namespace L4 { /* Forward declarations for our kernel object classes. */ class Task; class Thread; class Factory; class Irq; class K_semaphore; class Log; class Vm; class Kobject; template< typename T > class Cap; /** * \addtogroup l4_cap_api * * C++ interface for capabilities:
* \#include */ /*@{*/ /** * \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, 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(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 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(_c); } }; /** * \internal * \brief Specialization for \a void capabilities. */ template<> class Cap : public Cap_base { public: explicit Cap(void const *p) throw() : Cap_base(reinterpret_cast(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 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 obj = ... ; * L4::Cap icu = L4::cap_cast(obj); * \endcode */ template< typename T, typename F > inline Cap cap_cast(Cap const &c) throw() { (void)static_cast(reinterpret_cast(100)); return Cap(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 obj = ... ; * L4::Cap icu = L4::cap_reinterpret_cast(obj); * \endcode */ template< typename T, typename F > inline Cap cap_reinterpret_cast(Cap const &c) throw() { return Cap(c.cap()); } /*@}*/ /** * \addtogroup l4_kernel_object_api * * \#include */ /*@{*/ /** * \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 * { * L4_KOBJECT(Type) * }; * \endcode */ #define L4_KOBJECT(_class) L4_KOBJECT_DISABLE_COPY(_class) /** * \internal * \brief L4Re dynamic type information for \c void. */ static Type_info const kobject__m = { L4_KOBJECT_META_RTTI(void), 0, 0, 0 }; /** * \ingroup l4_kernel_object_api * \brief Base class for all kinds of kernel objects, referred to by * capabilities. * * \#include * * \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 friend Type_info const *kobject_typeid(); /** * \internal * \brief Get a pointer to the L4Re dynamic type information * for this class. * * \note This function is used by L4::kobject_typeid(). */ static Type_info const *__kobject_typeid() { return &kobject__m; } protected: /** * \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(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, 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 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 obj = ... ; * L4::Cap icu = L4::cap_dynamic_cast(obj); * \endcode */ template< typename T, typename F > inline Cap cap_dynamic_cast(Cap const &c) throw() { if (!c.is_valid()) return Cap::Invalid; Cap mc = cap_reinterpret_cast(c); Type_info const *m = kobject_typeid(); if (m->proto() && l4_error(mc->supports(m->proto())) > 0) return Cap(c.cap()); // FIXME: use generic checker #if 0 if (l4_error(mc->supports(T::kobject_proto())) > 0) return Cap(c.cap()); #endif return Cap::Invalid; } /*@}*/ }