L4Re - L4 Runtime Environment
dataspace_svr
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 
32 namespace L4Re { namespace Util {
33 
34 /**
35  * Dataspace server class.
36  *
37  * The default implementation of the interface provides a continuously
38  * mapped dataspace.
39  */
40 class Dataspace_svr
41 {
42 private:
43  typedef L4::Ipc::Gen_fpage<L4::Ipc::Snd_item> Snd_fpage;
44 public:
45  L4_RPC_LEGACY_DISPATCH(L4Re::Dataspace);
46 
47  typedef Snd_fpage::Map_type Map_type;
48  typedef Snd_fpage::Cacheopt Cache_type;
49  enum Rw_type {
50  Read_only = 0,
51  Writable = 1,
52  };
53 
54 
55  Dataspace_svr() throw()
56  : _ds_start(0), _ds_size(0), _map_flags(Snd_fpage::Map),
57  _cache_flags(Snd_fpage::Cached)
58  {}
59 
60  virtual ~Dataspace_svr() throw() {}
61 
62  /**
63  * Map a region of the dataspace
64  *
65  * \param offset Offset to start within data space
66  * \param local_addr Local address to map to.
67  * \param flags Map flags, see #L4Re::Dataspace::Map_flags.
68  * \param min_addr Defines start of receive window.
69  * \param max_addr Defines end of receive window.
70  * \param[out] memory Send fpage to map
71  *
72  * \retval 0 Success
73  * \retval <0 Error
74  */
75  int map(l4_addr_t offset, l4_addr_t local_addr, unsigned long flags,
76  l4_addr_t min_addr, l4_addr_t max_addr, L4::Ipc::Snd_fpage &memory);
77 
78  /**
79  * A hook that is called as the first operation in each map
80  * request.
81  * \param offs Offs param to map
82  * \param flags Flags param to map
83  * \param min Min param to map
84  * \param max Max param to map
85  * \retval <0 Error and the map request will be aborted with that error.
86  * \retval >=0 Success
87  *
88  * \see map
89  */
90  virtual int map_hook(l4_addr_t offs, unsigned long flags,
91  l4_addr_t min, l4_addr_t max)
92  {
93  (void)offs; (void)flags; (void)min; (void)max;
94  return 0;
95  }
96 
97  /**
98  * Return physical address for a virtual address
99  *
100  * \param offset Offset into the dataspace
101  * \param[out] phys_addr Physical address
102  * \param[out] phys_size Size of continious physical region
103  *
104  * \retval 0 Success
105  * \retval <0 Error
106  */
107  virtual int phys(l4_addr_t offset, l4_addr_t &phys_addr, l4_size_t &phys_size) throw();
108 
109  /**
110  * Take a reference to this dataspace
111  *
112  * Default does nothing.
113  */
114  virtual void take() throw()
115  {}
116 
117  /**
118  * Release a reference to this dataspace
119  *
120  * \return Number of references to the dataspace
121  *
122  * Default does nothing and returns always zero.
123  */
124  virtual unsigned long release() throw()
125  { return 0; }
126 
127  /**
128  * Copy from src dataspace to this destination dataspace
129  *
130  * \param dst_offs Offset into the destination dataspace
131  * \param src_id Local id of the source dataspace
132  * \param src_offs Offset into the source dataspace
133  * \param size Number of bytes to copy
134  *
135  * \retval >=0 Number of bytes copied
136  * \retval <0 An error occured. The error code may depend on the
137  * implementation.
138  */
139  virtual long copy(l4_addr_t dst_offs, l4_umword_t src_id,
140  l4_addr_t src_offs, unsigned long size) throw()
141  {
142  (void)dst_offs; (void)src_id; (void)src_offs; (void)size;
143  return -L4_ENODEV;
144  }
145 
146  /**
147  * Clear a region in the dataspace
148  *
149  * \param offs Start of the region
150  * \param size Size of the region
151  *
152  * \retval 0 Success
153  * \retval <0 Error
154  */
155  virtual long clear(unsigned long offs, unsigned long size) const throw();
156 
157  /**
158  * Allocate a region within a dataspace
159  *
160  * \param offset Offset in the dataspace, in bytes.
161  * \param size Size of the range, in bytes.
162  * \param access Access mode with which the memory backing the dataspace
163  * region should be allocated.
164  *
165  * \retval 0 Success
166  * \retval <0 Error
167  */
168  virtual long allocate(l4_addr_t offset, l4_size_t size, unsigned access) throw()
169  { (void)offset; (void)size; (void)access; return -L4_ENODEV; }
170 
171  /**
172  * Define the size of the flexpage to map
173  *
174  * \return flexpage size
175  */
176  virtual unsigned long page_shift() const throw()
177  { return L4_LOG2_PAGESIZE; }
178 
179  /**
180  * Return whether the dataspace is static
181  *
182  * \return True if dataspace is static
183  */
184  virtual bool is_static() const throw()
185  { return true; }
186 
187 
188  long op_map(L4Re::Dataspace::Rights rights,
189  unsigned long offset, l4_addr_t spot,
190  unsigned long flags, L4::Ipc::Snd_fpage &fp)
191  {
192  bool read_only = !is_writable() || !(rights & L4_CAP_FPAGE_W);
193 
194  if (read_only && (flags & 1))
195  return -L4_EPERM;
196 
197  return map(offset, spot, flags & 1, 0, ~0, fp);
198  }
199 
200  long op_take(L4Re::Dataspace::Rights)
201  { take(); return 0; }
202 
203  long op_release(L4Re::Dataspace::Rights)
204  {
205 
206  if (release() == 0 && !is_static())
207  {
208  //L4::cout << "MOE: R[" << this << "]: refs=" << ref_cnt() << '\n';
209  delete this;
210  return 0;
211  }
212  //L4::cout << "MOE: R[" << this << "]: refs=" << ref_cnt() << '\n';
213 
214  return 1;
215  }
216 
217  long op_allocate(L4Re::Dataspace::Rights rights,
218  l4_addr_t offset, l4_size_t size)
219  { return allocate(offset, size, rights & 3); }
220 
221  long op_copy_in(L4Re::Dataspace::Rights rights,
222  l4_addr_t dst_offs, L4::Ipc::Snd_fpage const &src_cap,
223  l4_addr_t src_offs, unsigned long sz)
224  {
225  if (!src_cap.id_received())
226  return -L4_EINVAL;
227 
228  if (!(rights & L4_CAP_FPAGE_W))
229  return -L4_EACCESS;
230 
231  if (sz == 0)
232  return L4_EOK;
233 
234  return copy(dst_offs, src_cap.data(), src_offs, sz);
235  }
236 
237  long op_phys(L4Re::Dataspace::Rights, l4_addr_t offset,
238  l4_addr_t &phys_addr, l4_size_t &phys_size)
239  { return phys(offset, phys_addr, phys_size); }
240 
241  long op_info(L4Re::Dataspace::Rights rights, L4Re::Dataspace::Stats &s)
242  {
243  s.size = size();
244  // only return writable if really writable
245  s.flags = rw_flags() & ~Writable;
246  if ((rights & L4_CAP_FPAGE_W) && is_writable())
247  s.flags |= Writable;
248  return L4_EOK;
249  }
250 
251  long op_clear(L4Re::Dataspace::Rights rights,
252  l4_addr_t offset, unsigned long size)
253  {
254  if ( !(rights & L4_CAP_FPAGE_W)
255  || !is_writable())
256  return -L4_EACCESS;
257 
258  return clear(offset, size);
259  }
260 
261 
262 protected:
263  unsigned long size() const throw()
264  { return _ds_size; }
265  unsigned long map_flags() const throw()
266  { return _map_flags; }
267  unsigned long rw_flags() const throw()
268  { return _rw_flags; }
269  unsigned long is_writable() const throw()
270  { return _rw_flags & Writable; }
271  unsigned long page_size() const throw()
272  { return 1UL << page_shift(); }
273  unsigned long round_size() const throw()
274  { return l4_round_size(size(), page_shift()); }
275  bool check_limit(l4_addr_t offset) const throw()
276  { return offset < round_size(); }
277 
278 protected:
279  void size(unsigned long size) throw() { _ds_size = size; }
280 
281  l4_addr_t _ds_start;
282  l4_size_t _ds_size;
283  Map_type _map_flags;
284  Cache_type _cache_flags;
285  Rw_type _rw_flags;
286 };
287 
288 }}