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/sys/cxx/types>
37#include <l4/re/consts>
38#include <l4/re/dataspace>
39
40namespace L4Re {
41
42/**
43 * \defgroup api_l4re_rm Region map API
44 * \ingroup api_l4re
45 * \brief Virtual address-space management.
46 *
47 * A region map object implements two protocols. The first protocol is the
48 * kernel page-fault protocol, to resolve page faults for threads running in an
49 * L4 task. The second protocol is the region map protocol itself, which allows
50 * managing the virtual memory address space of an L4 task.
51 *
52 * There are two basic concepts provided by the region map abstraction:
53 * - **Areas** are reserved ranges in the virtual memory address space.
54 * - **Regions** are areas that are backed by (part of) a dataspace, i.e.
55 *   accessing them results in access to the physical memory the dataspace
56 *   manages.
57 *
58 * Areas can be reserved for special use or for attaching a dataspace at a later
59 * time. When attaching a dataspace, the user can instruct the region map to
60 * search for an appropriate range to attach to. Regions are skipped in this
61 * search since they already have dataspaces attached to them, and areas are
62 * skipped because they are reserved.
63 *
64 * When a region map receives a page fault IPC, the region map will check if the
65 * faulting virtual address lies in a region. If yes, it will answer the page
66 * fault IPC with a mapping from the backing dataspace. If not, an error is
67 * returned.
68 *
69 * \see L4Re::Dataspace, L4Re::Rm,
70 * \see \ref l4re_concepts_ds_rm
71 */
72
73/**
74 * \brief Region map
75 * \headerfile rm l4/re/rm
76 * \ingroup api_l4re_rm
77 *
78 * \see \link api_l4re_rm Region map API \endlink.
79 */
80class L4_EXPORT Rm :
81  public L4::Kobject_t<Rm, L4::Pager, L4RE_PROTO_RM,
82                       L4::Type_info::Demand_t<1> >
83{
84public:
85  typedef L4Re::Dataspace::Offset Offset;
86
87  /// Result values for detach operation.
88  enum Detach_result
89  {
90    Detached_ds  = 0,      ///< Detached data sapce.
91    Kept_ds      = 1,      ///< Kept data space.
92    Split_ds     = 2,      ///< Splitted data space, and done.
93    Detach_result_mask = 3,
94
95    Detach_again = 4,      ///< Detached data space, more to do.
96  };
97
98
99  enum Region_flag_shifts
100  {
101    /// Start of Rm cache bits
102    Caching_shift    = Dataspace::F::Caching_shift,
103  };
104
105  /** Rm flags definitions. */
106  struct F
107  {
108    /// Flags for attach operation.
109    enum Attach_flags : l4_uint32_t
110    {
111      /// Search for a suitable address range.
112      Search_addr  = 0x20000,
113      /// Search only in area, or map into area.
114      In_area      = 0x40000,
115      /// Eagerly map the attached data space in.
116      Eager_map    = 0x80000,
117      /// Mask of all attach flags.
118      Attach_mask  = 0xf0000,
119    };
120
121    L4_TYPES_FLAGS_OPS_DEF(Attach_flags);
122
123    enum Region_flags : l4_uint16_t
124    {
125      /// Region rights
126      Rights_mask = 0x0f,
127      R         = Dataspace::F::R,
128      W         = Dataspace::F::W,
129      X         = Dataspace::F::X,
130      RW        = Dataspace::F::RW,
131      RX        = Dataspace::F::RX,
132      RWX       = Dataspace::F::RWX,
133
134      /// Free the portion of the data space after detach
135      Detach_free = 0x200,
136      /// Region has a pager
137      Pager       = 0x400,
138      /// Region is reserved (blocked)
139      Reserved    = 0x800,
140
141
142      /// Mask of all Rm cache bits
143      Caching_mask   = Dataspace::F::Caching_mask,
144      /// Cache bits for normal cacheable memory
145      Cache_normal   = Dataspace::F::Normal,
146      /// Cache bits for buffered (write combining) memory
147      Cache_buffered = Dataspace::F::Bufferable,
148      /// Cache bits for uncached memory
149      Cache_uncached = Dataspace::F::Uncacheable,
150
151      /// Mask for all bits for cache options and rights.
152      Ds_map_mask    = 0xff,
153
154      /// Mask of all region flags
155      Region_flags_mask = 0xffff,
156    };
157
158    L4_TYPES_FLAGS_OPS_DEF(Region_flags);
159
160    friend constexpr Dataspace::Flags map_flags(Region_flags rf)
161    {
162      return Dataspace::Flags((l4_uint16_t)rf & Ds_map_mask);
163    }
164
165    struct Flags : L4::Types::Flags_ops_t<Flags>
166    {
167      l4_uint32_t raw;
168      Flags() = default;
169      explicit constexpr Flags(l4_uint32_t f) : raw(f) {}
170      constexpr Flags(Attach_flags rf) : raw((l4_uint32_t)rf) {}
171      constexpr Flags(Region_flags rf) : raw((l4_uint32_t)rf) {}
172
173      friend constexpr Dataspace::Flags map_flags(Flags f)
174      {
175        return Dataspace::Flags(f.raw & Ds_map_mask);
176      }
177
178      constexpr Region_flags region_flags() const
179      {
180        return Region_flags(raw & Region_flags_mask);
181      }
182
183      constexpr Attach_flags attach_flags() const
184      {
185        return Attach_flags(raw & Attach_mask);
186      }
187
188      constexpr bool r() const { return raw & L4_FPAGE_RO; }
189      constexpr bool w() const { return raw & L4_FPAGE_W; }
190      constexpr bool x() const { return raw & L4_FPAGE_X; }
191      constexpr unsigned cap_rights() const
192      { return w() ? L4_CAP_FPAGE_RW : L4_CAP_FPAGE_RO; }
193    };
194
195    friend constexpr Flags operator | (Region_flags l, Attach_flags r)
196    { return Flags(l) | Flags(r); }
197
198    friend constexpr Flags operator | (Attach_flags l, Region_flags r)
199    { return Flags(l) | Flags(r); }
200  };
201
202  using Attach_flags = F::Attach_flags;
203  using Region_flags = F::Region_flags;
204  using Flags = F::Flags;
205
206  /// Flags for detach operation
207  enum Detach_flags
208  {
209    /**
210     * \brief Do an unmap of the exact region given.
211     * \internal
212     *
213     * This flag is useful for _detach().
214     *
215     * Using this mode for detach, unmaps the exact region given.
216     * This has the effect that parts of regions may stay in the address space.
217     */
218    Detach_exact   = 1,
219    /**
220     * \brief Do an unmap of all overlapping regions.
221     * \internal
222     *
223     * This flag is useful for _detach().
224     *
225     * Using this mode for detach, unmaps all regions that overlap with
226     * the given region.
227     */
228    Detach_overlap = 2,
229
230    /**
231     * \brief Do not free the detached data space, ignore the F::Detach_free
232     * \internal
233     *
234     * This flag is useful for _detach().
235     *
236     */
237    Detach_keep = 4,
238  };
239
240  /**
241   * \brief Reserve the given area in the region map.
242   * \param[in,out] start  The virtual start address of the area to reserve.
243   *                       Returns the start address of the area.
244   * \param         size   The size of the area to reserve (in bytes).
245   * \param         flags  Flags for the reserved area (see
246   *                       #L4Re::Rm::F::Region_flags and
247   *                       #L4Re::Rm::F::Attach_flags).
248   * \param         align  Alignment of area if searched as bits (log2 value).
249   * \retval 0                  Success
250   * \retval -L4_EADDRNOTAVAIL  The given area cannot be reserved.
251   * \retval <0                 IPC errors
252   *
253   * This function reserves an area within the virtual address space managed
254   * by the region map. There are two kinds of areas available:
255   * - Reserved areas (\a flags = F::Reserved), where no data spaces can be
256   *   attached
257   * - Special purpose areas (\a flags = 0), where data spaces can be attached
258   *   to the area via the F::In_area flag and a start address within the area
259   *   itself.
260   *
261   * \note When searching for a free place in the virtual address space
262   * (with \a flags = F::Search_addr), the space between \a start and the end of
263   * the virtual address space is searched.
264   */
265  long reserve_area(l4_addr_t *start, unsigned long size,
266                    Flags flags = Flags(0),
267                    unsigned char align = L4_PAGESHIFT) const noexcept
268  { return reserve_area_t::call(c(), start, size, flags, align); }
269
270  L4_RPC_NF(long, reserve_area, (L4::Ipc::In_out<l4_addr_t *> start,
271                                 unsigned long size,
272                                 Flags flags,
273                                 unsigned char align));
274
275  /**
276   * \brief Reserve the given area in the region map.
277   * \param[in,out] start  The virtual start address of the area to reserve.
278   *                       Returns the start address of the area.
279   * \param         size   The size of the area to reserve (in bytes).
280   * \param         flags  Flags for the reserved area (see F::Region_flags and
281   *                       F::Attach_flags).
282   * \param         align  Alignment of area if searched as bits (log2 value).
283   * \retval 0                  Success
284   * \retval -L4_EADDRNOTAVAIL  The given area cannot be reserved.
285   * \retval <0                 IPC errors
286   *
287   * For more information, please refer to the analogous function
288   * \see L4Re::Rm::reserve_area.
289   */
290  template< typename T >
291  long reserve_area(T **start, unsigned long size,
292                    Flags flags = Flags(0),
293                    unsigned char align = L4_PAGESHIFT) const noexcept
294  { return reserve_area_t::call(c(), (l4_addr_t*)start, size, flags, align); }
295
296  /**
297   * \brief Free an area from the region map.
298   *
299   * \param addr  An address within the area to free.
300   * \retval 0           Success
301   * \retval -L4_ENOENT  No area found.
302   * \retval <0          IPC errors
303   *
304   * \note The data spaces that are attached to that area are not detached by
305   *       this operation.
306   * \see reserve_area() for more information about areas.
307   */
308  L4_RPC(long, free_area, (l4_addr_t addr));
309
310  L4_RPC_NF(long, attach, (L4::Ipc::In_out<l4_addr_t *> start,
311                           unsigned long size, Flags flags,
312                           L4::Ipc::Opt<L4::Ipc::Cap<Dataspace> > mem,
313                           Offset offs, unsigned char align,
314                           L4::Ipc::Opt<l4_cap_idx_t> client_cap));
315
316  L4_RPC_NF(long, detach, (l4_addr_t addr, unsigned long size, unsigned flags,
317                           l4_addr_t &start, l4_addr_t &rsize,
318                           l4_cap_idx_t &mem_cap));
319
320  /**
321   * \brief Attach a data space to a region.
322   *
323   * \param[in,out]  start  Virtual start address where the region manager
324   *                        shall attach the data space. Will be rounded down to
325   *                        the nearest start of a page.
326   *                        If #L4Re::Rm::F::Search_addr is given this value is
327   *                        used as the start address to search for a free
328   *                        virtual memory region and the resulting address is
329   *                        returned here.
330   *                        If #L4Re::Rm::F::In_area is given the value is used
331   *                        as a selector for the area (see
332   *                        #L4Re::Rm::reserve_area) to attach the data space
333   *                        to.
334   * \param          size   Size of the data space to attach (in bytes). Will be
335   *                        rounded up to the nearest multiple of the page size.
336   * \param          flags  The flags control how and with which rights the
337   *                        dataspace is attached to the region. See
338   *                        #L4Re::Rm::F::Attach_flags and
339   *                        #L4Re::Rm::F::Region_flags. The caller must specify
340   *                        the desired rights of the attached region
341   *                        explicitly. The default set of rights is empty. If
342   *                        the `F::Eager_map` flag is set this function may
343   *                        also return L4Re::Dataspace::map error codes if the
344   *                        mapping fails.
345   * \param          mem    Data space.
346   * \param          offs   Offset into the data space to use.
347   * \param          align  Alignment of the virtual region, log2-size, default:
348   *                        a page (#L4_PAGESHIFT). This is only meaningful if
349   *                        the #L4Re::Rm::F::Search_addr flag is used.
350   *
351   * \retval 0                  Success
352   * \retval -L4_ENOENT         No area could be found (see
353   *                            #L4Re::Rm::F::In_area)
354   * \retval -L4_EPERM          Operation not allowed.
355   * \retval -L4_EINVAL
356   * \retval -L4_EADDRNOTAVAIL  The given address is not available.
357   * \retval <0                 IPC errors
358   *
359   * Makes the whole or parts of a data space visible in the virtual memory
360   * of the corresponding task. The corresponding region in the virtual
361   * address space is backed with the contents of the dataspace.
362   *
363   * \note When searching for a free place in the virtual address space,
364   * the space between \a start and the end of the virtual address space is
365   * searched.
366   *
367   * \note There is no region object created, instead the region is
368   *       defined by a virtual address within this range (see #L4Re::Rm::find).
369   */
370  long attach(l4_addr_t *start, unsigned long size, Flags flags,
371              L4::Ipc::Cap<Dataspace> mem, Offset offs = 0,
372              unsigned char align = L4_PAGESHIFT) const noexcept;
373
374  /**
375   * \copydoc L4Re::Rm::attach
376   */
377  template< typename T >
378  long attach(T **start, unsigned long size, Flags flags,
379              L4::Ipc::Cap<Dataspace> mem, Offset offs = 0,
380              unsigned char align = L4_PAGESHIFT) const noexcept
381  {
382    union X { l4_addr_t a; T* t; };
383    X *x = reinterpret_cast<X*>(start);
384    return attach(&x->a, size, flags, mem, offs, align);
385  }
386
387#if __cplusplus >= 201103L
388  template< typename T >
389  class Unique_region
390  {
391  private:
392    T _addr;
393    L4::Cap<Rm> _rm;
394
395  public:
396    Unique_region(Unique_region const &) = delete;
397    Unique_region &operator = (Unique_region const &) = delete;
398
399    Unique_region() noexcept
400    : _addr(0), _rm(L4::Cap<Rm>::Invalid) {}
401
402    explicit Unique_region(T addr) noexcept
403    : _addr(addr), _rm(L4::Cap<Rm>::Invalid) {}
404
405    Unique_region(T addr, L4::Cap<Rm> const &rm) noexcept
406    : _addr(addr), _rm(rm) {}
407
408    Unique_region(Unique_region &&o) noexcept : _addr(o.get()), _rm(o._rm)
409    { o.release(); }
410
411    Unique_region &operator = (Unique_region &&o) noexcept
412    {
413      if (&o != this)
414        {
415          if (_rm.is_valid())
416            _rm->detach(l4_addr_t(_addr), 0);
417          _rm = o._rm;
418          _addr = o.release();
419        }
420      return *this;
421    }
422
423    ~Unique_region() noexcept
424    {
425      if (_rm.is_valid())
426        _rm->detach(l4_addr_t(_addr), 0);
427    }
428
429    T get() const noexcept
430    { return _addr; }
431
432    T release() noexcept
433    {
434      _rm = L4::Cap<Rm>::Invalid;
435      return _addr;
436    }
437
438    void reset(T addr, L4::Cap<Rm> const &rm) noexcept
439    {
440      if (_rm.is_valid())
441        _rm->detach(l4_addr_t(_addr), 0);
442
443      _rm = rm;
444      _addr = addr;
445    }
446
447    void reset() noexcept
448    { reset(0, L4::Cap<Rm>::Invalid); }
449
450    bool is_valid() const noexcept
451    { return _rm.is_valid(); }
452
453    /** \brief Dereference the pointer. */
454    T operator * () const noexcept { return _addr; }
455
456    /** \brief Member access for the object. */
457    T operator -> () const noexcept { return _addr; }
458  };
459
460  template< typename T >
461  long attach(Unique_region<T> *start, unsigned long size, Flags flags,
462              L4::Ipc::Cap<Dataspace> mem, Offset offs = 0,
463              unsigned char align = L4_PAGESHIFT) const noexcept
464  {
465    l4_addr_t addr = (l4_addr_t)start->get();
466
467    long res = attach(&addr, size, flags, mem, offs, align);
468    if (res < 0)
469      return res;
470
471    start->reset((T)addr, L4::Cap<Rm>(cap()));
472    return res;
473  }
474#endif
475
476  /**
477   * \brief Detach a region from the address space.
478   *
479   * \param      addr  Virtual address of region, any address within the
480   *                   region is valid.
481   * \param[out] mem   Dataspace that is affected. Give 0 if not interested.
482   * \param      task  This argument specifies the task where the pages are
483   *                   unmapped. Provide L4::Cap<L4::Task>::Invalid for none.
484   *                   The default is the current task.
485   *
486   * \retval #Detach_result  On success.
487   * \retval -L4_ENOENT      No region found.
488   * \retval <0              IPC errors
489   *
490   * Frees a region in the virtual address space given by addr (address type).
491   * The corresponding part of the address space is now available again.
492   */
493  int detach(l4_addr_t addr, L4::Cap<Dataspace> *mem,
494             L4::Cap<L4::Task> const &task = This_task) const noexcept;
495
496  /**
497   * \copydoc L4Re::Rm::detach
498   */
499  int detach(void *addr, L4::Cap<Dataspace> *mem,
500             L4::Cap<L4::Task> const &task = This_task) const noexcept;
501
502  /**
503   * \brief Detach all regions of the specified interval.
504   *
505   * \param      start  Start of area to detach, must be within region.
506   * \param      size   Size of of area to detach (in bytes).
507   * \param[out] mem    Dataspace that is affected. Give 0 if not interested.
508   * \param      task   This argument specifies the task where the pages are
509   *                    unmapped. Provide L4::Cap<L4::Task>::Invalid for none.
510   *                    The default is the current task.
511   *
512   * \retval #Detach_result  On success.
513   * \retval -L4_ENOENT      No region found.
514   * \retval <0              IPC errors
515   *
516   * Frees all regions within the interval given by start and size. If a
517   * region overlaps the start or the end of the interval this region is only
518   * detached partly. If the interval is within one region the original region
519   * is split up into two separate regions.
520   */
521  int detach(l4_addr_t start, unsigned long size, L4::Cap<Dataspace> *mem,
522             L4::Cap<L4::Task> const &task) const noexcept;
523
524  /**
525   * \brief Find a region given an address and size.
526   *
527   * \param[in,out] addr  Address to look for. Returns the start address of the
528   *                      found region.
529   * \param[in,out] size  Size of the area to look for (in bytes). Returns the
530   *                      size of the found region (in bytes).
531   * \param[out] offset  Offset at the beginning of the region within the
532   *                     associated dataspace.
533   * \param[out] flags   Region flags, see F::Region_flags (and F::In_area).
534   * \param[out] m       Associated dataspace or paging service.
535   *
536   * \retval 0           Success
537   * \retval -L4_EPERM   Operation not allowed.
538   * \retval -L4_ENOENT  No region found.
539   * \retval <0          IPC errors
540   *
541   * This function returns the properties of the region that contains the area
542   * described by the addr and size parameter. If no such region is found but
543   * a reserved area, the area is returned and F::In_area is set in `flags`.
544   * Note, in the case of an area the `offset` and `m` return values are
545   * invalid.
546   *
547   * \verbatim
548                     size-out
549                   /           \
550                  /             \
551              addr-out           \
552                 ^________________\
553     ------------|----------------|------------------
554     |           | Region         |       Dataspace |
555     |           |_______|___|____|                 |
556     ------------|-------|---|-----------------------
557      \         /        |\ /
558       \       /         | |> size-in
559       offset-out        |
560                         |> addr-in
561     \endverbatim
562   *
563   *
564   * \note The value of the size input parameter should be 1 to assure that a
565   *       region can be determined unambiguously.
566   *
567   */
568  int find(l4_addr_t *addr, unsigned long *size, Offset *offset,
569           L4Re::Rm::Flags *flags, L4::Cap<Dataspace> *m) noexcept
570  { return find_t::call(c(), addr, size, flags, offset, m); }
571
572  L4_RPC_NF(int, find, (L4::Ipc::In_out<l4_addr_t *> addr,
573                        L4::Ipc::In_out<unsigned long *> size,
574                        L4Re::Rm::Flags *flags, Offset *offset,
575                        L4::Ipc::As_value<L4::Cap<Dataspace> > *m));
576
577  /**
578   * A range of virtual addresses.
579   */
580  struct Range
581  {
582    /// First address of the range.
583    l4_addr_t start;
584    /// Last address of the range.
585    l4_addr_t end;
586  };
587
588  /**
589   * A region is a range of virtual addresses which is backed by a dataspace.
590   *
591   * \see api_l4re_rm
592   */
593  using Region = Range;
594
595  /**
596   * An area is a range of virtual addresses which is reserved,
597   * see L4Re::Rm::reserve_area().
598   *
599   * \see api_l4re_rm
600   */
601  using Area = Range;
602
603  /**
604   * Return the list of regions whose starting addresses are higher or equal to
605   * `start` in the address space managed by this region map.
606   *
607   * \param       start   Virtual address from where to start searching.
608   * \param[out]  regions List of regions found in this region map.
609   *
610   * \retval >=0  Number of returned regions in the `regions` array.
611   * \retval <0   IPC errors
612   *
613   * \note The returned list of regions might not be complete and the caller
614   *       shall use the function repeatedly with a start address one larger
615   *       that the end address of the last region from the previous call.
616   */
617  L4_RPC(long, get_regions, (l4_addr_t start, L4::Ipc::Ret_array<Range> regions));
618
619  /**
620   * Return the list of areas whose starting addresses are higher or equal to
621   * `start` in the address space managed by this region map.
622   *
623   * \param       start Virtual address from where to start searching.
624   * \param[out]  areas List of areas found in this region map.
625   *
626   * \retval >=0  Number of returned areas in the `areas` array.
627   * \retval <0   IPC errors
628   *
629   * \note The returned list of areas might not be complete and the caller
630   *       shall use the function repeatedly with a start address one larger
631   *       than the end address of the last area from the previous call.
632   */
633
634  L4_RPC(long, get_areas, (l4_addr_t start, L4::Ipc::Ret_array<Range> areas));
635
636  int detach(l4_addr_t start, unsigned long size, L4::Cap<Dataspace> *mem,
637             L4::Cap<L4::Task> task, unsigned flags) const noexcept;
638
639  typedef L4::Typeid::Rpcs<attach_t, detach_t, find_t,
640                           reserve_area_t, free_area_t,
641                           get_regions_t, get_areas_t> Rpcs;
642};
643
644
645inline int
646Rm::detach(l4_addr_t addr, L4::Cap<Dataspace> *mem,
647           L4::Cap<L4::Task> const &task) const noexcept
648{  return detach(addr, 1, mem, task, Detach_overlap); }
649
650inline int
651Rm::detach(void *addr, L4::Cap<Dataspace> *mem,
652           L4::Cap<L4::Task> const &task) const noexcept
653{  return detach((l4_addr_t)addr, 1, mem, task, Detach_overlap); }
654
655inline int
656Rm::detach(l4_addr_t addr, unsigned long size, L4::Cap<Dataspace> *mem,
657           L4::Cap<L4::Task> const &task) const noexcept
658{  return detach(addr, size, mem, task, Detach_exact); }
659
660};
661