1// vi:set ft=cpp: -*- Mode: C++ -*-
2/**
3 * \file
4 * \brief Abstract capability-allocator interface
5 */
6/*
7 * (c) 2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
8 *          Alexander Warg <warg@os.inf.tu-dresden.de>
9 *     economic rights: Technische Universität Dresden (Germany)
10 *
11 * This file is part of TUD:OS and distributed under the terms of the
12 * GNU General Public License 2.
13 * Please see the COPYING-GPL-2 file for details.
14 *
15 * As a special exception, you may use this file as part of a free software
16 * library without restriction.  Specifically, if other files instantiate
17 * templates or use macros or inline functions from this file, or you compile
18 * this file and link it with other files to produce an executable, this
19 * file does not by itself cause the resulting executable to be covered by
20 * the GNU General Public License.  This exception does not however
21 * invalidate any other reasons why the executable file might be covered by
22 * the GNU General Public License.
23 */
24
25#pragma once
26
27#include <l4/sys/task>
28#include <l4/sys/smart_capability>
29#include <l4/re/consts>
30#include <l4/cxx/type_traits>
31
32namespace L4Re {
33
34/**
35 * \addtogroup l4re_cap_api
36 */
37/*@{*/
38/**
39 * \brief Capability allocator interface.
40 */
41class Cap_alloc
42{
43private:
44  void operator = (Cap_alloc const &);
45
46protected:
47  Cap_alloc(Cap_alloc const &) {}
48  Cap_alloc() {}
49
50public:
51
52  /**
53   * \brief Allocate a capability
54   * \return Capability of type void
55   */
56  virtual L4::Cap<void> alloc() noexcept = 0;
57  virtual void take(L4::Cap<void> cap) noexcept = 0;
58
59  /**
60   * \brief Allocate a capability
61   * \return Capability of type T
62   */
63  template< typename T >
64  L4::Cap<T> alloc() noexcept
65  { return L4::cap_cast<T>(alloc()); }
66
67  /**
68   * \brief Free a capability
69   * \param cap          Capability to free.
70   * \param task         If set, task to unmap the capability from.
71   * \param unmap_flags  Flags for unmap, see l4_unmap_flags_t.
72   */
73  virtual void free(L4::Cap<void> cap, l4_cap_idx_t task = L4_INVALID_CAP,
74                       unsigned unmap_flags = L4_FP_ALL_SPACES) noexcept = 0;
75  virtual bool release(L4::Cap<void> cap, l4_cap_idx_t task = L4_INVALID_CAP,
76                       unsigned unmap_flags = L4_FP_ALL_SPACES) noexcept = 0;
77
78  /**
79   * \brief Destructor.
80   */
81  virtual ~Cap_alloc() = 0;
82
83  /**
84   * \brief Construct an instance of a capability allocator.
85   * \param ca  Capability allocator
86   * \return Instance of a capability allocator.
87   */
88  template< typename CAP_ALLOC >
89  static inline L4Re::Cap_alloc *
90  get_cap_alloc(CAP_ALLOC &ca)
91  {
92    struct CA : public L4Re::Cap_alloc
93    {
94      CAP_ALLOC &_ca;
95      L4::Cap<void> alloc() noexcept override { return _ca.alloc(); }
96      void take(L4::Cap<void> cap) noexcept override { _ca.take(cap); }
97
98      void free(L4::Cap<void> cap, l4_cap_idx_t task = L4_INVALID_CAP,
99            unsigned unmap_flags = L4_FP_ALL_SPACES) noexcept override
100      { _ca.free(cap, task, unmap_flags); }
101
102      bool release(L4::Cap<void> cap, l4_cap_idx_t task,
103                   unsigned unmap_flags) noexcept override
104      { return _ca.release(cap, task, unmap_flags); }
105
106      void operator delete(void *) {}
107
108      CA(CAP_ALLOC &ca) : _ca(ca) {}
109    };
110
111    static CA _ca(ca);
112    return &_ca;
113  }
114};
115
116template<typename ALLOC>
117struct Cap_alloc_t : ALLOC, L4Re::Cap_alloc
118{
119  template<typename ...ARGS>
120  Cap_alloc_t(ARGS &&...args) : ALLOC(cxx::forward<ARGS>(args)...) {}
121
122  L4::Cap<void> alloc() noexcept override { return ALLOC::alloc(); }
123  void take(L4::Cap<void> cap) noexcept override { ALLOC::take(cap); }
124
125  void free(L4::Cap<void> cap, l4_cap_idx_t task = L4_INVALID_CAP,
126            unsigned unmap_flags = L4_FP_ALL_SPACES) noexcept override
127  { ALLOC::free(cap, task, unmap_flags); }
128
129  bool release(L4::Cap<void> cap, l4_cap_idx_t task,
130               unsigned unmap_flags) noexcept override
131  { return ALLOC::release(cap, task, unmap_flags); }
132
133  void operator delete(void *) {}
134};
135
136inline
137Cap_alloc::~Cap_alloc()
138{}
139
140extern Cap_alloc *virt_cap_alloc;
141
142/**
143 * \brief Helper for Unique_cap and Unique_del_cap
144 * \ingroup api_l4re_util
145 */
146template< unsigned long Unmap_flags = L4_FP_ALL_SPACES >
147class Smart_cap_auto
148{
149private:
150  Cap_alloc *_ca;
151
152public:
153  Smart_cap_auto() : _ca(0) {}
154  Smart_cap_auto(Cap_alloc *ca) : _ca(ca) {}
155
156  void free(L4::Cap_base &c)
157  {
158    if (c.is_valid() && _ca)
159      _ca->free(L4::Cap<void>(c.cap()), This_task, Unmap_flags);
160
161    invalidate(c);
162  }
163
164  static void invalidate(L4::Cap_base &c)
165  {
166    if (c.is_valid())
167      c.invalidate();
168  }
169
170  static L4::Cap_base copy(L4::Cap_base const &src)
171  {
172    L4::Cap_base r = src;
173    invalidate(const_cast<L4::Cap_base &>(src));
174    return r;
175  }
176};
177
178/**
179 * Helper for Ref_cap and Ref_del_cap.
180 */
181template< unsigned long Unmap_flags = L4_FP_ALL_SPACES >
182class Smart_count_cap
183{
184private:
185  Cap_alloc *_ca;
186
187public:
188  Smart_count_cap() : _ca(nullptr) {}
189  Smart_count_cap(Cap_alloc *ca) : _ca(ca) {}
190  /**
191   * Free operation for L4::Smart_cap
192   * (decrement ref count and delete if 0).
193   */
194  void free(L4::Cap_base &c) noexcept
195  {
196    if (c.is_valid())
197      {
198        if (_ca && _ca->release(L4::Cap<void>(c.cap()), This_task, Unmap_flags))
199          c.invalidate();
200      }
201  }
202
203  /**
204   * Invalidate operation for L4::Smart_cap.
205   */
206  static void invalidate(L4::Cap_base &c) noexcept
207  {
208    if (c.is_valid())
209      c.invalidate();
210  }
211
212  /**
213   * Copy operation for L4::Smart_cap (increment ref count).
214   */
215  L4::Cap_base copy(L4::Cap_base const &src)
216  {
217    if (src.is_valid())
218      _ca->take(L4::Cap<void>(src.cap()));
219    return src;
220  }
221};
222/*@}*/
223
224}
225