L4Re - L4 Runtime Environment
rm
Go to the documentation of this file.
1 // -*- Mode: C++ -*-
2 // vim:ft=cpp
3 /**
4  * \file
5  * \brief Region mapper interface
6  */
7 /*
8  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
9  * Alexander Warg <warg@os.inf.tu-dresden.de>,
10  * Björn Döbel <doebel@os.inf.tu-dresden.de>,
11  * Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
12  * economic rights: Technische Universität Dresden (Germany)
13  *
14  * This file is part of TUD:OS and distributed under the terms of the
15  * GNU General Public License 2.
16  * Please see the COPYING-GPL-2 file for details.
17  *
18  * As a special exception, you may use this file as part of a free software
19  * library without restriction. Specifically, if other files instantiate
20  * templates or use macros or inline functions from this file, or you compile
21  * this file and link it with other files to produce an executable, this
22  * file does not by itself cause the resulting executable to be covered by
23  * the GNU General Public License. This exception does not however
24  * invalidate any other reasons why the executable file might be covered by
25  * the GNU General Public License.
26  */
27 #pragma once
28 
29 #include <l4/sys/types.h>
30 #include <l4/sys/l4int.h>
31 #include <l4/sys/capability>
32 #include <l4/re/protocols.h>
33 #include <l4/sys/pager>
34 #include <l4/sys/cxx/ipc_iface>
35 #include <l4/sys/cxx/ipc_ret_array>
36 #include <l4/re/consts>
37 #include <l4/re/dataspace>
38 
39 namespace L4Re {
40 
41 /**
42  * \defgroup api_l4re_rm Region map API
43  * \ingroup api_l4re
44  * \brief Virtual address-space management.
45  *
46  * The central purpose of the region-map API is to provide means to manage the
47  * virtual memory address space of an L4 task. A region-map object implements
48  * two protocols. The first protocol is the kernel page-fault protocol, to resolve
49  * page faults for threads running in an L4 task. The second protocol is
50  * the region-map protocol itself, that allows to attach a data-space object
51  * to a region of the virtual address space.
52  *
53  * There are two basic concepts provided by a region-map abstraction:
54  * - Regions provide a means to create a view to a data space (or parts of a
55  * data space).
56  * - Areas provide a means to reserve areas in a virtual memory address space
57  * for special purposes. A reserved area is skipped when searching for
58  * an available range of virtual memory, or may be explicitly used to search
59  * only within that area.
60  *
61  * \see L4Re::Dataspace, L4Re::Rm
62  */
63 
64 /**
65  * \brief Region map
66  * \headerfile rm l4/re/rm
67  * \ingroup api_l4re_rm
68  */
69 class L4_EXPORT Rm :
70  public L4::Kobject_t<Rm, L4::Pager, L4RE_PROTO_RM,
71  L4::Type_info::Demand_t<1> >
72 {
73 public:
74  /// Result values for detach operation.
75  enum Detach_result
76  {
77  Detached_ds = 0, ///< Detached data sapce.
78  Kept_ds = 1, ///< Kept data space.
79  Split_ds = 2, ///< Splitted data space, and done.
80  Detach_result_mask = 3,
81 
82  Detach_again = 4, ///< Detached data space, more to do.
83  };
84 
85  /// Flags for regions.
86  enum Region_flags
87  {
88  Read_only = 0x01, ///< Region is read-only
89  /// Free the portion of the data space after detach
90  Detach_free = 0x02,
91  Pager = 0x04, ///< Region has a pager
92  Reserved = 0x08, ///< Region is reserved (blocked)
93 
94  /// Start of Rm cache bits
95  Caching_shift = 8,
96  /// Shift value for Dataspace to Rm cache bits
97  Caching_ds_shift = Caching_shift - Dataspace::Map_caching_shift,
98  /// Mask of all Rm cache bits
99  Caching = Dataspace::Map_caching_mask << Caching_ds_shift,
100  /// Cache bits for normal cacheable memory
101  Cache_normal = Dataspace::Map_normal << Caching_ds_shift,
102  /// Cache bits for buffered (write combining) memory
103  Cache_buffered = Dataspace::Map_bufferable << Caching_ds_shift,
104  /// Cache bits for uncached memory
105  Cache_uncached = Dataspace::Map_uncacheable << Caching_ds_shift,
106 
107  Region_flags = Caching | 0x0f, ///< Mask of all region flags
108  };
109 
110  /// Flags for attach operation.
111  enum Attach_flags
112  {
113  Search_addr = 0x20, ///< Search for a suitable address range.
114  In_area = 0x40, ///< Search only in area, or map into area.
115  Eager_map = 0x80, ///< Eagerly map the attached data space in.
116 
117  Attach_flags = 0xf0, ///< Mask of all attach flags.
118  };
119 
120  /// Flags for detach operation
121  enum Detach_flags
122  {
123  /**
124  * \brief Do an unmap of the exact region given.
125  * \internal
126  *
127  * This flag is useful for _detach().
128  *
129  * Using this mode for detach, unmaps the exact region given.
130  * This has the effect that parts of regions may stay in the address space.
131  */
132  Detach_exact = 1,
133  /**
134  * \brief Do an unmap of all overlapping regions.
135  * \internal
136  *
137  * This flag is useful for _detach().
138  *
139  * Using this mode for detach, unmaps all regions that overlap with
140  * the given region.
141  */
142  Detach_overlap = 2,
143 
144  /**
145  * \brief Do not free the detached data space, ignore the #Detach_free
146  * \internal
147  *
148  * This flag is useful for _detach().
149  *
150  */
151  Detach_keep = 4,
152  };
153 
154 
155  template< typename T >
156  class Auto_region
157  {
158  private:
159  T _addr;
160  mutable L4::Cap<Rm> _rm;
161 
162  public:
163  Auto_region() throw()
164  : _addr(0), _rm(L4::Cap<Rm>::Invalid) {}
165 
166  explicit Auto_region(T addr) throw()
167  : _addr(addr), _rm(L4::Cap<Rm>::Invalid) {}
168 
169  Auto_region(T addr, L4::Cap<Rm> const &rm) throw()
170  : _addr(addr), _rm(rm) {}
171 
172  Auto_region(Auto_region const &o) throw() : _addr(o.get()), _rm(o._rm)
173  { o.release(); }
174 
175  Auto_region &operator = (Auto_region const &o) throw()
176  {
177  if (&o != this)
178  {
179  if (_rm.is_valid())
180  _rm->detach(l4_addr_t(_addr), 0);
181  _rm = o._rm;
182  _addr = o.release();
183  }
184  return *this;
185  }
186 
187  ~Auto_region() throw()
188  {
189  if (_rm.is_valid())
190  _rm->detach(l4_addr_t(_addr), 0);
191  }
192 
193  T get() const throw() { return _addr; }
194  T release() const throw() { _rm = L4::Cap<Rm>::Invalid; return _addr; }
195  void reset(T addr, L4::Cap<Rm> const &rm) throw()
196  {
197  if (_rm.is_valid())
198  _rm->detach(l4_addr_t(_addr), 0);
199 
200  _rm = rm;
201  _addr = addr;
202  }
203 
204  void reset() throw()
205  { reset(0, L4::Cap<Rm>::Invalid); }
206 
207  /** \brief Dereference the pointer. */
208  T operator * () const throw() { return _addr; }
209 
210  /** \brief Member access for the object. */
211  T operator -> () const throw() { return _addr; }
212 
213  } L4_DEPRECATED("use L4Re::Rm::Unique_region");
214 
215  /**
216  * \brief Reserve the given area in the region map.
217  * \param[in,out] start The virtual start address of the area to reserve.
218  * Returns the start address of the area.
219  * \param size The size of the area to reserve (in bytes).
220  * \param flags Flags for the reserved area (see
221  * #L4Re::Rm::Region_flags and #L4Re::Rm::Attach_flags).
222  * \param align Alignment of area if searched as bits (log2 value).
223  * \retval 0 Success
224  * \retval -L4_EADDRNOTAVAIL The given area cannot be reserved.
225  * \retval <0 IPC errors
226  *
227  * This function reserves an area within the virtual address space implemented
228  * by the region map. There are two kinds of areas available:
229  * - Reserved areas (\a flags = #Reserved), where no data spaces can be
230  * attached
231  * - Special purpose areas (\a flags = 0), where data spaces can be attached
232  * to the area via the #In_area flag and a start address within the area
233  * itself.
234  *
235  * \note When searching for a free place in the virtual address space
236  * (with \a flags = Search_addr), the space between \a start and the end of
237  * the virtual address space is searched.
238  */
239  long reserve_area(l4_addr_t *start, unsigned long size,
240  unsigned flags = 0,
241  unsigned char align = L4_PAGESHIFT) const throw()
242  { return reserve_area_t::call(c(), start, size, flags, align); }
243 
244  L4_RPC_NF(long, reserve_area, (L4::Ipc::In_out<l4_addr_t *> start,
245  unsigned long size,
246  unsigned flags,
247  unsigned char align));
248 
249  /**
250  * \brief Reserve the given area in the region map.
251  * \param[in,out] start The virtual start address of the area to reserve.
252  * Returns the start address of the area.
253  * \param size The size of the area to reserve (in bytes).
254  * \param flags Flags for the reserved area (see #Region_flags and
255  * #Attach_flags).
256  * \param align Alignment of area if searched as bits (log2 value).
257  * \retval 0 Success
258  * \retval -L4_EADDRNOTAVAIL The given area cannot be reserved.
259  * \retval <0 IPC errors
260  *
261  * For more information, please refer to the analogous function
262  * \see L4Re::Rm::reserve_area.
263  */
264  template< typename T >
265  long reserve_area(T **start, unsigned long size,
266  unsigned flags = 0,
267  unsigned char align = L4_PAGESHIFT) const throw()
268  { return reserve_area_t::call(c(), (l4_addr_t*)start, size, flags, align); }
269 
270  /**
271  * \brief Free an area from the region map.
272  *
273  * \param addr An address within the area to free.
274  * \retval 0 Success
275  * \retval -L4_ENOENT No area found.
276  * \retval <0 IPC errors
277  *
278  * \note The data spaces that are attached to that area are not detached by
279  * this operation.
280  * \see reserve_area() for more information about areas.
281  */
282  L4_RPC(long, free_area, (l4_addr_t addr));
283 
284  L4_RPC_NF(long, attach, (L4::Ipc::In_out<l4_addr_t *> start,
285  unsigned long size, unsigned long flags,
286  L4::Ipc::Opt<L4::Ipc::Cap<Dataspace> > mem,
287  l4_addr_t offs, unsigned char align,
288  L4::Ipc::Opt<l4_cap_idx_t> client_cap));
289 
290  L4_RPC_NF(long, detach, (l4_addr_t addr, unsigned long size, unsigned flags,
291  l4_addr_t &start, l4_addr_t &rsize,
292  l4_cap_idx_t &mem_cap));
293 
294  /**
295  * \brief Attach a data space to a region.
296  *
297  * \param[in,out] start Virtual start address where the region manager
298  * shall attach the data space.
299  * If #L4Re::Rm::Search_addr is given this value is
300  * used as the start address to search for a free
301  * virtual memory region and the resulting address is
302  * returned here.
303  * If #L4Re::Rm::In_area is given the value is used as
304  * a selector for the area (see
305  * #L4Re::Rm::reserve_area) to attach the data space
306  * to.
307  * \param size Size of the data space to attach (in bytes)
308  * \param flags Flags, see #L4Re::Rm::Attach_flags and
309  * #L4Re::Rm::Region_flags. If the `Eager_map` flag is
310  * set this function may also return
311  * L4Re::Dataspace::map error codes if the mapping
312  * fails.
313  * \param mem Data space
314  * \param offs Offset into the data space to use
315  * \param align Alignment of the virtual region, log2-size, default:
316  * a page (#L4_PAGESHIFT). This is only meaningful if
317  * the #L4Re::Rm::Search_addr flag is used.
318  *
319  * \retval 0 Success
320  * \retval -L4_ENOENT No area could be found (see #L4Re::Rm::In_area)
321  * \retval -L4_EPERM Operation not allowed.
322  * \retval -L4_EINVAL
323  * \retval -L4_EADDRNOTAVAIL The given address is not available.
324  * \retval <0 IPC errors
325  *
326  * Makes the whole or parts of a data space visible in the virtual memory
327  * of the corresponding task. The corresponding region in the virtual
328  * address space is backed with the contents of the dataspace.
329  *
330  * \note When searching for a free place in the virtual address space,
331  * the space between \a start and the end of the virtual address space is
332  * searched.
333  *
334  * \note There is no region object created, instead the region is
335  * defined by a virtual address within this range (see #L4Re::Rm::find).
336  */
337  long attach(l4_addr_t *start, unsigned long size, unsigned long flags,
338  L4::Ipc::Cap<Dataspace> mem, l4_addr_t offs = 0,
339  unsigned char align = L4_PAGESHIFT) const throw();
340 
341  /**
342  * \copydoc L4Re::Rm::attach
343  */
344  template< typename T >
345  long attach(T **start, unsigned long size, unsigned long flags,
346  L4::Ipc::Cap<Dataspace> mem, l4_addr_t offs = 0,
347  unsigned char align = L4_PAGESHIFT) const throw()
348  {
349  union X { l4_addr_t a; T* t; };
350  X *x = reinterpret_cast<X*>(start);
351  return attach(&x->a, size, flags, mem, offs, align);
352  }
353 
354 #pragma GCC diagnostic push
355 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
356  template< typename T >
357  long attach(Auto_region<T> *start, unsigned long size, unsigned long flags,
358  L4::Ipc::Cap<Dataspace> mem, l4_addr_t offs = 0,
359  unsigned char align = L4_PAGESHIFT) const throw()
360  {
361  l4_addr_t addr = (l4_addr_t)start->get();
362 
363  long res = attach(&addr, size, flags, mem, offs, align);
364  if (res < 0)
365  return res;
366 
367  start->reset((T)addr, L4::Cap<Rm>(cap()));
368  return res;
369  }
370 #pragma GCC diagnostic pop
371 
372 #if __cplusplus >= 201103L
373  template< typename T >
374  class Unique_region
375  {
376  private:
377  T _addr;
378  L4::Cap<Rm> _rm;
379 
380  public:
381  Unique_region(Unique_region const &) = delete;
382  Unique_region &operator = (Unique_region const &) = delete;
383 
384  Unique_region() noexcept
385  : _addr(0), _rm(L4::Cap<Rm>::Invalid) {}
386 
387  explicit Unique_region(T addr) noexcept
388  : _addr(addr), _rm(L4::Cap<Rm>::Invalid) {}
389 
390  Unique_region(T addr, L4::Cap<Rm> const &rm) noexcept
391  : _addr(addr), _rm(rm) {}
392 
393  Unique_region(Unique_region &&o) noexcept : _addr(o.get()), _rm(o._rm)
394  { o.release(); }
395 
396  Unique_region &operator = (Unique_region &&o) noexcept
397  {
398  if (&o != this)
399  {
400  if (_rm.is_valid())
401  _rm->detach(l4_addr_t(_addr), 0);
402  _rm = o._rm;
403  _addr = o.release();
404  }
405  return *this;
406  }
407 
408  ~Unique_region() noexcept
409  {
410  if (_rm.is_valid())
411  _rm->detach(l4_addr_t(_addr), 0);
412  }
413 
414  T get() const noexcept
415  { return _addr; }
416 
417  T release() noexcept
418  {
419  _rm = L4::Cap<Rm>::Invalid;
420  return _addr;
421  }
422 
423  void reset(T addr, L4::Cap<Rm> const &rm) noexcept
424  {
425  if (_rm.is_valid())
426  _rm->detach(l4_addr_t(_addr), 0);
427 
428  _rm = rm;
429  _addr = addr;
430  }
431 
432  void reset() noexcept
433  { reset(0, L4::Cap<Rm>::Invalid); }
434 
435  bool is_valid() const noexcept
436  { return _rm.is_valid(); }
437 
438  /** \brief Dereference the pointer. */
439  T operator * () const noexcept { return _addr; }
440 
441  /** \brief Member access for the object. */
442  T operator -> () const noexcept { return _addr; }
443  };
444 
445  template< typename T >
446  long attach(Unique_region<T> *start, unsigned long size, unsigned long flags,
447  L4::Ipc::Cap<Dataspace> mem, l4_addr_t offs = 0,
448  unsigned char align = L4_PAGESHIFT) const noexcept
449  {
450  l4_addr_t addr = (l4_addr_t)start->get();
451 
452  long res = attach(&addr, size, flags, mem, offs, align);
453  if (res < 0)
454  return res;
455 
456  start->reset((T)addr, L4::Cap<Rm>(cap()));
457  return res;
458  }
459 #endif
460 
461  /**
462  * \brief Detach a region from the address space.
463  *
464  * \param addr Virtual address of region, any address within the
465  * region is valid.
466  * \param[out] mem Dataspace that is affected. Give 0 if not interested.
467  * \param task This argument specifies the task where the pages are
468  * unmapped. Provide L4::Cap<L4::Task>::Invalid for none.
469  * The default is the current task.
470  *
471  * \retval #Detach_result On success.
472  * \retval -L4_ENOENT No region found.
473  * \retval <0 IPC errors
474  *
475  * Frees a region in the virtual address space given by addr (address type).
476  * The corresponding part of the address space is now available again.
477  */
478  int detach(l4_addr_t addr, L4::Cap<Dataspace> *mem,
479  L4::Cap<L4::Task> const &task = This_task) const throw();
480 
481  /**
482  * \copydoc L4Re::Rm::detach
483  */
484  int detach(void *addr, L4::Cap<Dataspace> *mem,
485  L4::Cap<L4::Task> const &task = This_task) const throw();
486 
487  /**
488  * \brief Detach all regions of the specified interval.
489  *
490  * \param start Start of area to detach, must be within region.
491  * \param size Size of of area to detach (in bytes).
492  * \param[out] mem Dataspace that is affected. Give 0 if not interested.
493  * \param task This argument specifies the task where the pages are
494  * unmapped. Provide L4::Cap<L4::Task>::Invalid for none.
495  * The default is the current task.
496  *
497  * \retval #Detach_result On success.
498  * \retval -L4_ENOENT No region found.
499  * \retval <0 IPC errors
500  *
501  * Frees all regions within the interval given by start and size. If a
502  * region overlaps the start or the end of the interval this region is only
503  * detached partly. If the interval is within one region the original region
504  * is split up into two separate regions.
505  */
506  int detach(l4_addr_t start, unsigned long size, L4::Cap<Dataspace> *mem,
507  L4::Cap<L4::Task> const &task) const throw();
508 
509  /**
510  * \brief Find a region given an address and size.
511  *
512  * \param addr Address to look for
513  * \param size Size of the area to look for (in bytes).
514  * \param[out] addr Start address of the found region.
515  * \param[out] size Size of the found region (in bytes).
516  * \param[out] offset Offset at the beginning of the region within the
517  * associated dataspace.
518  * \param[out] flags Region flags, see #Region_flags (and #In_area).
519  * \param[out] m Associated dataspace or paging service.
520  *
521  * \retval 0 Success
522  * \retval -L4_EPERM Operation not allowed.
523  * \retval -L4_ENOENT No region found.
524  * \retval <0 IPC errors
525  *
526  * This function returns the properties of the region that contains the area
527  * described by the addr and size parameter. If no such region is found but
528  * a reserved area, the area is returned and #In_area is set in `flags`.
529  * Note, in the case of an area the `offset` and `m` return values are
530  * invalid.
531  *
532  * \verbatim
533  size-out
534  / \
535  / \
536  addr-out \
537  ^________________\
538  ------------|----------------|------------------
539  | | Region | Dataspace |
540  | |_______|___|____| |
541  ------------|-------|---|-----------------------
542  \ / |\ /
543  \ / | |> size-in
544  offset-out |
545  |> addr-in
546  \endverbatim
547  *
548  *
549  * \note The value of the size input parameter should be 1 to assure that a
550  * region can be determined unambiguously.
551  *
552  */
553  int find(l4_addr_t *addr, unsigned long *size, l4_addr_t *offset,
554  unsigned *flags, L4::Cap<Dataspace> *m) throw()
555  { return find_t::call(c(), addr, size, flags, offset, m); }
556 
557  L4_RPC_NF(int, find, (L4::Ipc::In_out<l4_addr_t *> addr,
558  L4::Ipc::In_out<unsigned long *> size,
559  unsigned *flags, l4_addr_t *offset,
560  L4::Ipc::As_value<L4::Cap<Dataspace> > *m));
561 
562  struct Region
563  {
564  l4_addr_t start;
565  l4_addr_t end;
566  l4_addr_t offset;
567  L4::Cap<Dataspace> ds;
568  };
569 
570  struct Area
571  {
572  l4_addr_t start;
573  l4_addr_t end;
574  };
575 
576  L4_RPC(long, get_regions, (l4_addr_t start, L4::Ipc::Ret_array<Region> regions));
577  L4_RPC(long, get_areas, (l4_addr_t start, L4::Ipc::Ret_array<Area> areas));
578 
579  int detach(l4_addr_t start, unsigned long size, L4::Cap<Dataspace> *mem,
580  L4::Cap<L4::Task> task, unsigned flags) const throw();
581 
582  typedef L4::Typeid::Rpcs<attach_t, detach_t, find_t,
583  reserve_area_t, free_area_t,
584  get_regions_t, get_areas_t> Rpcs;
585 };
586 
587 
588 inline int
589 Rm::detach(l4_addr_t addr, L4::Cap<Dataspace> *mem,
590  L4::Cap<L4::Task> const &task) const throw()
591 { return detach(addr, 1, mem, task, Detach_overlap); }
592 
593 inline int
594 Rm::detach(void *addr, L4::Cap<Dataspace> *mem,
595  L4::Cap<L4::Task> const &task) const throw()
596 { return detach((l4_addr_t)addr, 1, mem, task, Detach_overlap); }
597 
598 inline int
599 Rm::detach(l4_addr_t addr, unsigned long size, L4::Cap<Dataspace> *mem,
600  L4::Cap<L4::Task> const &task) const throw()
601 { return detach(addr, size, mem, task, Detach_exact); }
602 
603 };
604