]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/obj_space_phys_util.cpp
Update
[l4.git] / kernel / fiasco / src / kern / obj_space_phys_util.cpp
1 INTERFACE:
2
3 #include "assert_opt.h"
4 #include "obj_space_types.h"
5 #include "ram_quota.h"
6
7 template< typename SPACE >
8 class Obj_space_phys
9 {
10 public:
11   typedef Obj::Attr Attr;
12   typedef Obj::Capability Capability;
13   typedef Obj::Entry Entry;
14   typedef Kobject_iface *Phys_addr;
15
16   typedef Obj::Cap_addr V_pfn;
17   typedef Cap_diff V_pfc;
18   typedef Order Page_order;
19
20   bool v_lookup(V_pfn const &virt, Phys_addr *phys,
21                 Page_order *size, Attr *attribs);
22
23   L4_fpage::Rights v_delete(V_pfn virt, Order size,
24                             L4_fpage::Rights page_attribs);
25   Obj::Insert_result v_insert(Phys_addr phys, V_pfn const &virt, Order size,
26                               Attr page_attribs);
27
28   Capability lookup(Cap_index virt);
29
30 private:
31   enum
32   {
33     Slots_per_dir = Config::PAGE_SIZE / sizeof(void*)
34   };
35
36   struct Cap_table { Entry e[Obj::Caps_per_page]; };
37   struct Cap_dir   { Cap_table *d[Slots_per_dir]; };
38   Cap_dir *_dir;
39
40   Ram_quota *ram_quota() const
41   {
42     assert_opt (this);
43     return SPACE::ram_quota(this);
44   }
45 };
46
47 // ------------------------------------------------------------------------
48 INTERFACE [obj_space_virt]:
49
50 #include "cxx/type_traits"
51
52 /**
53  * Allows to override the virtually mapped object space Space
54  * by the multi-level table based structure.
55  *
56  * This is useful for Vm or Io spaces that never run threads, and
57  * saves the overhead of software page-table walks and phys-to-virt
58  * translations for capability lookup.
59  */
60 template<typename BASE>
61 class Obj_space_phys_override :
62   public BASE,
63   Obj_space_phys< Obj_space_phys_override<BASE> >
64 {
65   typedef Obj_space_phys< Obj_space_phys_override<BASE> > Obj_space;
66
67 public:
68   using BASE::ram_quota;
69   static Ram_quota *ram_quota(Obj_space const *obj_sp)
70   { return static_cast<Obj_space_phys_override<BASE> const *>(obj_sp)->ram_quota(); }
71
72   bool FIASCO_FLATTEN
73   v_lookup(typename Obj_space::V_pfn const &virt,
74            typename Obj_space::Phys_addr *phys,
75            typename Obj_space::Page_order *size,
76            typename Obj_space::Attr *attribs) override
77   { return Obj_space::v_lookup(virt, phys, size, attribs); }
78
79   L4_fpage::Rights FIASCO_FLATTEN
80   v_delete(typename Obj_space::V_pfn virt, Order size,
81            L4_fpage::Rights page_attribs) override
82   { return Obj_space::v_delete(virt, size, page_attribs); }
83
84   Obj::Insert_result FIASCO_FLATTEN
85   v_insert(typename Obj_space::Phys_addr phys,
86            typename Obj_space::V_pfn const &virt,
87            Order size,
88            typename Obj_space::Attr page_attribs) override
89   { return Obj_space::v_insert(phys, virt, size, page_attribs); }
90
91   typename Obj_space::Capability FIASCO_FLATTEN
92   lookup(Cap_index virt) override
93   { return Obj_space::lookup(virt); }
94
95   typename Obj_space::V_pfn FIASCO_FLATTEN
96   obj_map_max_address() const override
97   { return Obj_space::obj_map_max_address(); }
98
99   void FIASCO_FLATTEN caps_free() override
100   { Obj_space::caps_free(); }
101
102   template<typename ...ARGS>
103   Obj_space_phys_override(ARGS &&...args) : BASE(cxx::forward<ARGS>(args)...) {}
104 };
105
106 // ------------------------------------------------------------------------
107 INTERFACE [!obj_space_virt]:
108
109 #include "cxx/type_traits"
110
111 /**
112  * The noop version when Space already uses a multi-level array for
113  * the object space.
114  */
115 template<typename BASE>
116 class Obj_space_phys_override : public BASE
117 {
118 public:
119   template<typename ...ARGS>
120   Obj_space_phys_override(ARGS &&...args) : BASE(cxx::forward<ARGS>(args)...) {}
121 };
122
123 //----------------------------------------------------------------------------
124 IMPLEMENTATION:
125
126 #include <cstring>
127 #include <cassert>
128
129 #include "atomic.h"
130 #include "config.h"
131 #include "cpu.h"
132 #include "kmem_alloc.h"
133 #include "mem.h"
134 #include "mem_layout.h"
135 #include "ram_quota.h"
136 #include "static_assert.h"
137
138 PUBLIC template< typename SPACE >
139 inline NEEDS["static_assert.h"]
140 Obj_space_phys<SPACE>::Obj_space_phys()
141 {
142   static_assert(sizeof(Cap_dir) == Config::PAGE_SIZE, "cap_dir size mismatch");
143   _dir = (Cap_dir*)Kmem_alloc::allocator()->q_unaligned_alloc(ram_quota(), Config::PAGE_SIZE);
144   if (_dir)
145     Mem::memset_mwords(_dir, 0, Config::PAGE_SIZE / sizeof(Mword));
146 }
147
148 PRIVATE template< typename SPACE >
149 typename Obj_space_phys<SPACE>::Entry *
150 Obj_space_phys<SPACE>::get_cap(Cap_index index)
151 {
152   if (EXPECT_FALSE(!_dir))
153     return 0;
154
155   unsigned d_idx = cxx::int_value<Cap_index>(index) >> Obj::Caps_per_page_ld2;
156   if (EXPECT_FALSE(d_idx >= Slots_per_dir))
157     return 0;
158
159   Cap_table *tab = _dir->d[d_idx];
160
161   if (EXPECT_FALSE(!tab))
162     return 0;
163
164   unsigned offs  = cxx::get_lsb(cxx::int_value<Cap_index>(index), Obj::Caps_per_page_ld2);
165   return &tab->e[offs];
166 }
167
168 PRIVATE template< typename SPACE >
169 typename Obj_space_phys<SPACE>::Entry *
170 Obj_space_phys<SPACE>::caps_alloc(Cap_index virt)
171 {
172   static_assert(sizeof(Cap_table) == Config::PAGE_SIZE, "cap table size mismatch");
173   unsigned d_idx = cxx::int_value<Cap_index>(virt) >> Obj::Caps_per_page_ld2;
174   if (EXPECT_FALSE(d_idx >= Slots_per_dir))
175     return 0;
176
177   void *mem = Kmem_alloc::allocator()->q_unaligned_alloc(ram_quota(), Config::PAGE_SIZE);
178
179   if (!mem)
180     return 0;
181
182   Obj::add_cap_page_dbg_info(mem, SPACE::get_space(this),  cxx::int_value<Cap_index>(virt));
183
184   Mem::memset_mwords(mem, 0, Config::PAGE_SIZE / sizeof(Mword));
185
186   Cap_table *tab = _dir->d[d_idx] = (Cap_table*)mem;
187   return &tab->e[ cxx::get_lsb(cxx::int_value<Cap_index>(virt), Obj::Caps_per_page_ld2)];
188 }
189
190 PUBLIC template< typename SPACE >
191 void
192 Obj_space_phys<SPACE>::caps_free()
193 {
194   if (!_dir)
195     return;
196
197   Cap_dir *d = _dir;
198   _dir = 0;
199
200   Kmem_alloc *a = Kmem_alloc::allocator();
201   for (unsigned i = 0; i < Slots_per_dir; ++i)
202     {
203       if (!d->d[i])
204         continue;
205
206       Obj::remove_cap_page_dbg_info(d->d[i]);
207       a->q_unaligned_free(ram_quota(), Config::PAGE_SIZE, d->d[i]);
208     }
209
210   a->q_unaligned_free(ram_quota(), Config::PAGE_SIZE, d);
211 }
212
213 //
214 // Utilities for map<Obj_space_phys> and unmap<Obj_space_phys>
215 //
216
217 IMPLEMENT template< typename SPACE >
218 inline NEEDS[Obj_space_phys::get_cap]
219 bool FIASCO_FLATTEN
220 Obj_space_phys<SPACE>::v_lookup(V_pfn const &virt, Phys_addr *phys,
221                                 Page_order *size, Attr *attribs)
222 {
223   if (size) *size = Page_order(0);
224   Entry *cap = get_cap(virt);
225
226   if (EXPECT_FALSE(!cap))
227     {
228       if (size) *size = Page_order(Obj::Caps_per_page_ld2);
229       return false;
230     }
231
232   Capability c = *cap;
233
234   Obj::set_entry(virt, cap);
235   if (phys) *phys = c.obj();
236   if (c.valid() && attribs) *attribs = cap->rights();
237   return c.valid();
238 }
239
240 IMPLEMENT template< typename SPACE >
241 inline NEEDS [Obj_space_phys::get_cap]
242 typename Obj_space_phys<SPACE>::Capability FIASCO_FLATTEN
243 Obj_space_phys<SPACE>::lookup(Cap_index virt)
244 {
245   Capability *c = get_cap(virt);
246
247   if (EXPECT_FALSE(!c))
248     return Capability(0); // void
249
250   return *c;
251 }
252
253 PUBLIC template< typename SPACE >
254 inline
255 Kobject_iface *
256 Obj_space_phys<SPACE>::lookup_local(Cap_index virt, L4_fpage::Rights *rights)
257 {
258   Entry *c = get_cap(virt);
259
260   if (EXPECT_FALSE(!c))
261     return 0;
262
263   Capability cap = *c;
264
265   if (rights)
266     *rights = L4_fpage::Rights(cap.rights());
267
268   return cap.obj();
269 }
270
271
272 IMPLEMENT template< typename SPACE >
273 inline NEEDS[<cassert>, Obj_space_phys::get_cap]
274 L4_fpage::Rights FIASCO_FLATTEN
275 Obj_space_phys<SPACE>::v_delete(V_pfn virt, Page_order size,
276                                    L4_fpage::Rights page_attribs = L4_fpage::Rights::FULL())
277 {
278   (void)size;
279   assert (size == Page_order(0));
280   Capability *c = get_cap(virt);
281
282   if (c && c->valid())
283     {
284       if (page_attribs & L4_fpage::Rights::R())
285         c->invalidate();
286       else
287         c->del_rights(page_attribs);
288     }
289
290   return L4_fpage::Rights(0);
291 }
292
293 IMPLEMENT template< typename SPACE >
294 inline NEEDS[Obj_space_phys::caps_alloc]
295 typename Obj::Insert_result FIASCO_FLATTEN
296 Obj_space_phys<SPACE>::v_insert(Phys_addr phys, V_pfn const &virt, Page_order size,
297                                 Attr page_attribs)
298 {
299   (void)size;
300   assert (size == Page_order(0));
301
302   Entry *c = get_cap(virt);
303
304   if (!c && !(c = caps_alloc(virt)))
305     return Obj::Insert_err_nomem;
306
307   if (c->valid())
308     {
309       if (c->obj() == phys)
310         {
311           if (EXPECT_FALSE(c->rights() == page_attribs))
312             return Obj::Insert_warn_exists;
313
314           c->add_rights(page_attribs);
315           return Obj::Insert_warn_attrib_upgrade;
316         }
317       else
318         return Obj::Insert_err_exists;
319     }
320
321   Obj::set_entry(virt, c);
322   c->set(phys, page_attribs);
323   return Obj::Insert_ok;
324 }
325
326
327 PUBLIC template< typename SPACE >
328 inline
329 typename Obj_space_phys<SPACE>::V_pfn
330 Obj_space_phys<SPACE>::obj_map_max_address() const
331 {
332   return V_pfn(Slots_per_dir * Obj::Caps_per_page);
333 }
334
335 // ------------------------------------------------------------------------------
336 IMPLEMENTATION [debug]:
337
338 PUBLIC template< typename SPACE >
339 typename Obj_space_phys<SPACE>::Entry *
340 Obj_space_phys<SPACE>::jdb_lookup_cap(Cap_index index)
341 { return get_cap(index); }
342
343 // ------------------------------------------------------------------------------
344 IMPLEMENTATION [obj_space_virt && debug]:
345
346 PUBLIC template<typename BASE> static inline
347 Obj_space_phys_override<BASE> *
348 Obj_space_phys_override<BASE>::get_space(Obj_space *base)
349 { return static_cast<Obj_space_phys_override<BASE> *>(base); }
350
351 PUBLIC template<typename BASE>
352 Obj::Entry *
353 Obj_space_phys_override<BASE>::jdb_lookup_cap(Cap_index index) override
354 { return Obj_space::jdb_lookup_cap(index); }
355
356 // ------------------------------------------------------------------------------
357 IMPLEMENTATION [obj_space_virt && !debug]:
358
359 PUBLIC template<typename BASE> static inline
360 Obj_space_phys_override<BASE> *
361 Obj_space_phys_override<BASE>::get_space(Obj_space *)
362 { return 0; }