1// vi:set ft=cpp: -*- Mode: C++ -*-
2/*
3 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
4 *               Alexander Warg <warg@os.inf.tu-dresden.de>,
5 *               Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
6 *     economic rights: Technische Universität Dresden (Germany)
7 *
8 * This file is part of TUD:OS and distributed under the terms of the
9 * GNU General Public License 2.
10 * Please see the COPYING-GPL-2 file for details.
11 *
12 * As a special exception, you may use this file as part of a free software
13 * library without restriction.  Specifically, if other files instantiate
14 * templates or use macros or inline functions from this file, or you compile
15 * this file and link it with other files to produce an executable, this
16 * file does not by itself cause the resulting executable to be covered by
17 * the GNU General Public License.  This exception does not however
18 * invalidate any other reasons why the executable file might be covered by
19 * the GNU General Public License.
20 */
21#pragma once
22
23#include <cstring>
24#include <cstddef>
25#include <l4/sys/types.h>
26#include <l4/cxx/list>
27#include <l4/cxx/minmax>
28#include <l4/re/dataspace>
29#include <l4/re/dataspace-sys.h>
30#include <l4/sys/cxx/ipc_legacy>
31
32namespace L4Re { namespace Util {
33
34/**
35 * Dataspace server class.
36 *
37 * The default implementation of the interface provides a continuous dataspace
38 * with contiguous pages.
39 */
40class Dataspace_svr
41{
42private:
43  typedef L4::Ipc::Gen_fpage<L4::Ipc::Snd_item> Snd_fpage;
44public:
45  L4_RPC_LEGACY_DISPATCH(L4Re::Dataspace);
46
47  typedef Snd_fpage::Map_type Map_type;
48  typedef Snd_fpage::Cacheopt Cache_type;
49
50  Dataspace_svr() noexcept
51  : _ds_start(0), _ds_size(0), _map_flags(Snd_fpage::Map),
52    _cache_flags(Snd_fpage::Cached)
53  {}
54
55  virtual ~Dataspace_svr() noexcept {}
56
57  /**
58   * Map a region of the dataspace
59   *
60   * \param      offset      Offset to start within data space
61   * \param      local_addr  Local address to map to.
62   * \param      flags       Dataspace flags, see #L4Re::Dataspace::F::Flags.
63   * \param      min_addr    Defines start of receive window.
64   * \param      max_addr    Defines end of receive window.
65   * \param[out] memory      Send fpage to map
66   *
67   * \retval 0   Success
68   * \retval <0  Error
69   */
70  int map(Dataspace::Offset offset,
71          Dataspace::Map_addr local_addr,
72          Dataspace::Flags flags,
73          Dataspace::Map_addr min_addr,
74          Dataspace::Map_addr max_addr,
75          L4::Ipc::Snd_fpage &memory);
76
77  /**
78   * A hook that is called as the first operation in each map
79   *        request.
80   * \param offs  Offs param to map
81   * \param flags Flags param to map
82   * \param min   Min param to map
83   * \param max   Max param to map
84   * \retval <0   Error and the map request will be aborted with that error.
85   * \retval >=0  Success
86   *
87   * \see map
88   */
89  virtual int map_hook(Dataspace::Offset offs,
90                       Dataspace::Flags flags,
91                       Dataspace::Map_addr min,
92                       Dataspace::Map_addr max)
93  {
94    (void)offs; (void)flags; (void)min; (void)max;
95    return 0;
96  }
97
98  /**
99   * Take a reference to this dataspace
100   *
101   * Default does nothing.
102   */
103  virtual void take() noexcept
104  {}
105
106  /**
107   * Release a reference to this dataspace
108   *
109   * \return Number of references to the dataspace
110   *
111   * Default does nothing and returns always zero.
112   */
113  virtual unsigned long release() noexcept
114  { return 0; }
115
116  /**
117   * Copy from src dataspace to this destination dataspace
118   *
119   * \param dst_offs  Offset into the destination dataspace
120   * \param src_id    Local id of the source dataspace
121   * \param src_offs  Offset into the source dataspace
122   * \param size      Number of bytes to copy
123   *
124   * \retval >=0  Number of bytes copied
125   * \retval <0   An error occured. The error code may depend on the
126   *              implementation.
127   */
128  virtual long copy(l4_addr_t dst_offs, l4_umword_t src_id,
129                    l4_addr_t src_offs, unsigned long size) noexcept
130  {
131    (void)dst_offs; (void)src_id; (void)src_offs; (void)size;
132    return -L4_ENODEV;
133  }
134
135  /**
136   * Clear a region in the dataspace
137   *
138   * \param offs Start of the region
139   * \param size Size of the region
140   *
141   * \retval 0   Success
142   * \retval <0  Error
143   */
144  virtual long clear(unsigned long offs, unsigned long size) const noexcept;
145
146  /**
147   * Allocate a region within a dataspace
148   *
149   * \param offset  Offset in the dataspace, in bytes.
150   * \param size    Size of the range, in bytes.
151   * \param access  Access mode with which the memory backing the dataspace
152   *                region should be allocated.
153   *
154   * \retval 0   Success
155   * \retval <0  Error
156   */
157  virtual long allocate(l4_addr_t offset, l4_size_t size, unsigned access) noexcept
158  { (void)offset; (void)size; (void)access; return -L4_ENODEV; }
159
160  /**
161   * Define the size of the flexpage to map
162   *
163   * \return flexpage size
164   */
165  virtual unsigned long page_shift() const noexcept
166  { return L4_LOG2_PAGESIZE; }
167
168  /**
169   * Return whether the dataspace is static
170   *
171   * \return True if dataspace is static
172   */
173  virtual bool is_static() const noexcept
174  { return true; }
175
176
177  long op_map(L4Re::Dataspace::Rights rights,
178              L4Re::Dataspace::Offset offset,
179              L4Re::Dataspace::Map_addr spot,
180              L4Re::Dataspace::Flags flags,
181              L4::Ipc::Snd_fpage &fp)
182  {
183    auto rf = map_flags(rights);
184
185    if (!rf.w() && flags.w())
186      return -L4_EPERM;
187
188    return map(offset, spot, flags & rf, 0, ~0, fp);
189  }
190
191  long op_allocate(L4Re::Dataspace::Rights rights,
192                   L4Re::Dataspace::Offset offset,
193                   L4Re::Dataspace::Size size)
194  { return allocate(offset, size, rights & 3); }
195
196  long op_copy_in(L4Re::Dataspace::Rights rights,
197                  L4Re::Dataspace::Offset dst_offs,
198                  L4::Ipc::Snd_fpage const &src_cap,
199                  L4Re::Dataspace::Offset src_offs,
200                  L4Re::Dataspace::Size sz)
201  {
202    if (!src_cap.id_received())
203      return -L4_EINVAL;
204
205    if (!(rights & L4_CAP_FPAGE_W))
206      return -L4_EACCESS;
207
208    if (sz == 0)
209      return L4_EOK;
210
211    return copy(dst_offs, src_cap.data(), src_offs, sz);
212  }
213
214  long op_info(L4Re::Dataspace::Rights rights, L4Re::Dataspace::Stats &s)
215  {
216    s.size = size();
217    // only return writable if really writable
218    s.flags = Dataspace::Flags(0);
219    if (map_flags(rights).w())
220      s.flags |= Dataspace::F::W;
221    return L4_EOK;
222  }
223
224  long op_clear(L4Re::Dataspace::Rights rights,
225                L4Re::Dataspace::Offset offset,
226                L4Re::Dataspace::Size size)
227  {
228    if (!map_flags(rights).w())
229      return -L4_EACCESS;
230
231    return clear(offset, size);
232  }
233
234
235protected:
236  unsigned long size() const noexcept
237  { return _ds_size; }
238  unsigned long map_flags() const noexcept
239  { return _map_flags; }
240  unsigned long page_size() const noexcept
241  { return 1UL << page_shift(); }
242  unsigned long round_size() const noexcept
243  { return l4_round_size(size(), page_shift()); }
244  bool check_limit(l4_addr_t offset) const noexcept
245  { return offset < round_size(); }
246
247  L4Re::Dataspace::Flags
248  map_flags(L4Re::Dataspace::Rights rights = L4_CAP_FPAGE_W) const noexcept
249  {
250    auto f = (_rw_flags & L4Re::Dataspace::Flags(0x0f)) | L4Re::Dataspace::F::Caching_mask;
251    if (!(rights & L4_CAP_FPAGE_W))
252      f &= ~L4Re::Dataspace::F::W;
253
254    return f;
255  }
256
257protected:
258  void size(unsigned long size) noexcept { _ds_size = size; }
259
260  l4_addr_t _ds_start;
261  l4_size_t _ds_size;
262  Map_type _map_flags;
263  Cache_type _cache_flags;
264  L4Re::Dataspace::Flags _rw_flags;
265};
266
267}}
268