// vi:set ft=cpp: -*- Mode: C++ -*- /** * \file * \brief Abstract capability-allocator interface */ /* * (c) 2009 Adam Lackorzynski , * Alexander Warg * 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 namespace L4Re { /** * \addtogroup l4re_cap_api */ /*@{*/ /** * \brief Capability allocator interface. */ class Cap_alloc { private: void operator = (Cap_alloc const &); protected: Cap_alloc(Cap_alloc const &) {} Cap_alloc() {} public: /** * \brief Allocate a capability * \return Capability of type void */ virtual L4::Cap alloc() noexcept = 0; virtual void take(L4::Cap cap) noexcept = 0; /** * \brief Allocate a capability * \return Capability of type T */ template< typename T > L4::Cap alloc() noexcept { return L4::cap_cast(alloc()); } /** * \brief Free a capability * \param cap Capability to free. * \param task If set, task to unmap the capability from. * \param unmap_flags Flags for unmap, see l4_unmap_flags_t. */ virtual void free(L4::Cap cap, l4_cap_idx_t task = L4_INVALID_CAP, unsigned unmap_flags = L4_FP_ALL_SPACES) noexcept = 0; virtual bool release(L4::Cap cap, l4_cap_idx_t task = L4_INVALID_CAP, unsigned unmap_flags = L4_FP_ALL_SPACES) noexcept = 0; /** * \brief Destructor. */ virtual ~Cap_alloc() = 0; /** * \brief Construct an instance of a capability allocator. * \param ca Capability allocator * \return Instance of a capability allocator. */ template< typename CAP_ALLOC > static inline L4Re::Cap_alloc * get_cap_alloc(CAP_ALLOC &ca) { struct CA : public L4Re::Cap_alloc { CAP_ALLOC &_ca; L4::Cap alloc() noexcept override { return _ca.alloc(); } void take(L4::Cap cap) noexcept override { _ca.take(cap); } void free(L4::Cap cap, l4_cap_idx_t task = L4_INVALID_CAP, unsigned unmap_flags = L4_FP_ALL_SPACES) noexcept override { _ca.free(cap, task, unmap_flags); } bool release(L4::Cap cap, l4_cap_idx_t task, unsigned unmap_flags) noexcept override { return _ca.release(cap, task, unmap_flags); } void operator delete(void *) {} CA(CAP_ALLOC &ca) : _ca(ca) {} }; static CA _ca(ca); return &_ca; } }; template struct Cap_alloc_t : ALLOC, L4Re::Cap_alloc { template Cap_alloc_t(ARGS &&...args) : ALLOC(cxx::forward(args)...) {} L4::Cap alloc() noexcept override { return ALLOC::alloc(); } void take(L4::Cap cap) noexcept override { ALLOC::take(cap); } void free(L4::Cap cap, l4_cap_idx_t task = L4_INVALID_CAP, unsigned unmap_flags = L4_FP_ALL_SPACES) noexcept override { ALLOC::free(cap, task, unmap_flags); } bool release(L4::Cap cap, l4_cap_idx_t task, unsigned unmap_flags) noexcept override { return ALLOC::release(cap, task, unmap_flags); } void operator delete(void *) {} }; inline Cap_alloc::~Cap_alloc() {} extern Cap_alloc *virt_cap_alloc; /** * \brief Helper for Unique_cap and Unique_del_cap * \ingroup api_l4re_util */ template< unsigned long Unmap_flags = L4_FP_ALL_SPACES > class Smart_cap_auto { private: Cap_alloc *_ca; public: Smart_cap_auto() : _ca(0) {} Smart_cap_auto(Cap_alloc *ca) : _ca(ca) {} void free(L4::Cap_base &c) { if (c.is_valid() && _ca) _ca->free(L4::Cap(c.cap()), This_task, Unmap_flags); invalidate(c); } static void invalidate(L4::Cap_base &c) { if (c.is_valid()) c.invalidate(); } static L4::Cap_base copy(L4::Cap_base const &src) { L4::Cap_base r = src; invalidate(const_cast(src)); return r; } }; /** * Helper for Ref_cap and Ref_del_cap. */ template< unsigned long Unmap_flags = L4_FP_ALL_SPACES > class Smart_count_cap { private: Cap_alloc *_ca; public: Smart_count_cap() : _ca(nullptr) {} Smart_count_cap(Cap_alloc *ca) : _ca(ca) {} /** * Free operation for L4::Smart_cap * (decrement ref count and delete if 0). */ void free(L4::Cap_base &c) noexcept { if (c.is_valid()) { if (_ca && _ca->release(L4::Cap(c.cap()), This_task, Unmap_flags)) c.invalidate(); } } /** * Invalidate operation for L4::Smart_cap. */ static void invalidate(L4::Cap_base &c) noexcept { if (c.is_valid()) c.invalidate(); } /** * Copy operation for L4::Smart_cap (increment ref count). */ L4::Cap_base copy(L4::Cap_base const &src) { if (src.is_valid()) _ca->take(L4::Cap(src.cap())); return src; } }; /*@}*/ }