1 /*
2  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *               Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10 #pragma once
11 
12 #include <cstddef>
13 #include <l4/sys/types.h>
14 #include <l4/cxx/iostream>
15 #include <l4/cxx/list>
16 #include <l4/sys/cxx/ipc_epiface>
17 #include <l4/re/dataspace>
18 
19 #include "dma_space.h"
20 #include "server_obj.h"
21 #include "globals.h"
22 #include "quota.h"
23 
24 namespace Moe {
25 
26 /**
27  * Base class for all dataspace types.
28  *
29  * Provides common implementations of the Dataspace interface functions.
30  * The behaviour may be adapted by overwriting the provided virtual
31  * functions.
32  */
33 class Dataspace :
34   public L4::Epiface_t<Dataspace, L4Re::Dataspace, Server_object>,
35   public Q_object
36 {
37 public:
38   using Flags = L4Re::Dataspace::Flags;
39   enum { Cow_enabled = 0x100 };
40 
41   struct Address
42   {
43     l4_fpage_t fpage;
44     l4_addr_t offs;
45 
throwAddress46     Address(long error) throw() : offs(-1UL) { fpage.raw = error; }
47 
48     Address(l4_addr_t base, l4_addr_t size,
49             Flags flags,
throwAddress50             l4_addr_t offs = 0) throw()
51     : fpage(l4_fpage(base, size, flags.fpage_rights())),
52       offs(offs) {}
53 
bsAddress54     unsigned long bs() const throw() { return fpage.raw & L4_FPAGE_ADDR_MASK; }
szAddress55     unsigned long sz() const throw() { return 1 << l4_fpage_size(fpage); }
ofAddress56     unsigned long of() const throw() { return offs; }
fpAddress57     l4_fpage_t fp() const throw() { return fpage; }
58 
59     template< typename T >
adrAddress60     T adr() const throw() { return (T)(bs() + offs); }
61 
adrAddress62     void *adr() const throw() { return (void*)(bs() + offs); }
63 
is_nilAddress64     bool is_nil() const throw() { return offs == -1UL; }
65     /**
66      * \brief Get the error code that led to the invalid address.
67      * \pre is_nil() must return true.
68      */
errorAddress69     long error() const throw() { return fpage.raw; }
70 
71   };
72 
Dataspace(unsigned long size,Flags flags,unsigned char page_shift)73   Dataspace(unsigned long size, Flags flags,
74             unsigned char page_shift) throw()
75     : _size(size), _flags(flags), _page_shift(page_shift)
76   {}
77 
78 
size()79   unsigned long size() const throw() { return _size; }
80   virtual Address address(l4_addr_t ds_offset,
81                           Flags flags = L4Re::Dataspace::F::RWX,
82                           l4_addr_t hot_spot = 0,
83                           l4_addr_t min = 0, l4_addr_t max = ~0) const = 0;
84   virtual int copy_address(l4_addr_t ds_offset, Flags flags,
85                            l4_addr_t *copy_addr, unsigned long *copy_size) const = 0;
86 
87   virtual int pre_allocate(l4_addr_t offset, l4_size_t size, unsigned rights) = 0;
88 
can_cow()89   bool can_cow() const noexcept { return (bool)(_flags & Flags(Cow_enabled)); }
flags()90   Flags flags() const noexcept { return _flags; }
91 
92   Flags map_flags(L4Re::Dataspace::Rights rights = L4_CAP_FPAGE_W) const noexcept
93   {
94     auto f = (_flags & Flags(L4Re::Dataspace::F::Rights_mask))
95              | L4Re::Dataspace::F::Caching_mask;
96     if (!(rights & L4_CAP_FPAGE_W))
97       f &= ~L4Re::Dataspace::F::W;
98 
99     return f;
100   }
101 
~Dataspace()102   virtual ~Dataspace() {}
103 
page_shift()104   unsigned long page_shift() const throw() { return _page_shift; }
page_size()105   unsigned long page_size() const throw() { return 1UL << _page_shift; }
106 
107   virtual bool is_static() const throw() = 0;
108   virtual long clear(unsigned long offs, unsigned long size) const throw();
109 
110 protected:
size(unsigned long size)111   void size(unsigned long size) throw() { _size = size; }
112 
113 public:
round_size()114   unsigned long round_size() const throw()
115   { return l4_round_size(size(), page_shift()); }
check_limit(l4_addr_t offset)116   bool check_limit(l4_addr_t offset) const throw()
117   { return offset < round_size(); }
check_range(l4_addr_t offset,unsigned long sz)118   bool check_range(l4_addr_t offset, unsigned long sz) const throw()
119   { return offset < round_size() && size() - offset >= sz; }
120 
121 public:
122   int map(l4_addr_t offs, l4_addr_t spot, Flags flags,
123           l4_addr_t min, l4_addr_t max, L4::Ipc::Snd_fpage &memory);
124 
125   typedef Dma_space::Attributes Dma_attribs;
126   virtual int dma_map(Dma_space *dma, l4_addr_t offset, l4_size_t *size,
127                       Dma_attribs dma_attrs, Dma_space::Direction dir,
128                       Dma_space::Dma_addr *dma_addr);
129 
130   long op_map(L4Re::Dataspace::Rights rights,
131               L4Re::Dataspace::Offset offset,
132               L4Re::Dataspace::Map_addr spot,
133               L4Re::Dataspace::Flags flags, L4::Ipc::Snd_fpage &fp);
134 
op_allocate(L4Re::Dataspace::Rights rights,L4Re::Dataspace::Offset offset,L4Re::Dataspace::Size size)135   long op_allocate(L4Re::Dataspace::Rights rights,
136                    L4Re::Dataspace::Offset offset,
137                    L4Re::Dataspace::Size size)
138   { return pre_allocate(offset, size, rights & 3); }
139 
140   long op_copy_in(L4Re::Dataspace::Rights rights,
141                   L4Re::Dataspace::Offset dst_offs,
142                   L4::Ipc::Snd_fpage const &src_cap,
143                   L4Re::Dataspace::Offset src_offs,
144                   L4Re::Dataspace::Size sz);
145 
op_info(L4Re::Dataspace::Rights rights,L4Re::Dataspace::Stats & s)146   long op_info(L4Re::Dataspace::Rights rights, L4Re::Dataspace::Stats &s)
147   {
148     s.size = size();
149     s.flags = flags();
150     // only return writable if really writable
151     if (!(rights & L4_CAP_FPAGE_W))
152       s.flags &= ~L4Re::Dataspace::F::W;
153 
154     return L4_EOK;
155   }
156 
op_clear(L4Re::Dataspace::Rights rights,L4Re::Dataspace::Offset offset,L4Re::Dataspace::Size size)157   long op_clear(L4Re::Dataspace::Rights rights,
158                 L4Re::Dataspace::Offset offset,
159                 L4Re::Dataspace::Size size)
160   {
161     if (!map_flags(rights).w())
162       return -L4_EACCESS;
163 
164     return clear(offset, size);
165   }
166 
167 
168 private:
169   unsigned long  _size;
170   Flags _flags;
171   unsigned char  _page_shift;
172 };
173 
174 }
175 
176 
177 
178