]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/obj_space_virt_util.cpp
update
[l4.git] / kernel / fiasco / src / kern / obj_space_virt_util.cpp
1 INTERFACE:
2
3 #include "mem.h"
4 #include "mem_space.h"
5 #include "ram_quota.h"
6 #include "obj_space_types.h"
7
8 template<typename SPACE>
9 class Obj_space_virt
10 {
11 public:
12   typedef Obj::Attr Attr;
13   typedef Obj::Capability Capability;
14   typedef Obj::Entry Entry;
15   typedef Kobject_iface *Phys_addr;
16
17   typedef Obj::Cap_addr V_pfn;
18   typedef Cap_diff V_pfc;
19   typedef Order Page_order;
20
21   bool v_lookup(V_pfn const &virt, Phys_addr *phys,
22                 Page_order *size, Attr *attribs);
23
24   L4_fpage::Rights v_delete(V_pfn virt, Order size,
25                             L4_fpage::Rights page_attribs);
26   Obj::Insert_result v_insert(Phys_addr phys, V_pfn const &virt, Order size,
27                               Attr page_attribs);
28
29   Capability lookup(Cap_index virt);
30
31 private:
32   enum
33   {
34     // do not use the virtually mapped cap table in
35     // v_lookup and v_insert, because the map logic needs the kernel
36     // address for link pointers in the map-nodes and these addresses must
37     // be valid in all address spaces.
38     Optimize_local = 0,
39
40     Whole_space = 20,
41     Map_max_address = 1UL << 20, /* 20bit obj index */
42   };
43 };
44
45 IMPLEMENTATION:
46
47 #include <cstring>
48 #include <cassert>
49
50 #include "atomic.h"
51 #include "config.h"
52 #include "cpu.h"
53 #include "kdb_ke.h"
54 #include "kmem_alloc.h"
55 #include "mem_layout.h"
56
57 PRIVATE  template< typename SPACE >
58 static inline NEEDS["mem_layout.h"]
59 typename Obj_space_virt<SPACE>::Entry *
60 Obj_space_virt<SPACE>::cap_virt(Cap_index index)
61 { return reinterpret_cast<Entry*>(Mem_layout::Caps_start) + cxx::int_value<Cap_index>(index); }
62
63
64
65 PRIVATE template< typename SPACE >
66 inline NEEDS["mem_space.h", "mem_layout.h", Obj_space_virt::cap_virt]
67 typename Obj_space_virt<SPACE>::Entry *
68 Obj_space_virt<SPACE>::get_cap(Cap_index index)
69 {
70   Mem_space *ms = SPACE::mem_space(this);
71
72   Address phys = Address(ms->virt_to_phys((Address)cap_virt(index)));
73   if (EXPECT_FALSE(phys == ~0UL))
74     return 0;
75
76   return reinterpret_cast<Entry*>(Mem_layout::phys_to_pmem(phys));
77 }
78
79 PRIVATE  template< typename SPACE >
80 /*inline NEEDS["kmem_alloc.h", <cstring>, "ram_quota.h",
81                      Obj_space_virt::cap_virt]*/
82 typename Obj_space_virt<SPACE>::Entry *
83 Obj_space_virt<SPACE>::caps_alloc(Cap_index virt)
84 {
85   Address cv = (Address)cap_virt(virt);
86   void *mem = Kmem_alloc::allocator()->q_unaligned_alloc(SPACE::ram_quota(this), Config::PAGE_SIZE);
87
88   if (!mem)
89     return 0;
90
91   Obj::add_cap_page_dbg_info(mem, SPACE::get_space(this), cxx::int_value<Cap_index>(virt));
92
93   Mem::memset_mwords(mem, 0, Config::PAGE_SIZE / sizeof(Mword));
94
95   Mem_space::Status s;
96   s = SPACE::mem_space(this)->v_insert(
97       Mem_space::Phys_addr(Mem_space::kernel_space()->virt_to_phys((Address)mem)),
98       cxx::mask_lsb(Virt_addr(cv), Mem_space::Page_order(Config::PAGE_SHIFT)),
99       Mem_space::Page_order(Config::PAGE_SHIFT),
100       Mem_space::Attr(L4_fpage::Rights::RW()));
101       //| Mem_space::Page_referenced | Mem_space::Page_dirty);
102
103   switch (s)
104     {
105     case Mem_space::Insert_ok:
106       break;
107     case Mem_space::Insert_warn_exists:
108     case Mem_space::Insert_warn_attrib_upgrade:
109       assert (false);
110       break;
111     case Mem_space::Insert_err_exists:
112     case Mem_space::Insert_err_nomem:
113       Kmem_alloc::allocator()->q_unaligned_free(SPACE::ram_quota(this),
114           Config::PAGE_SIZE, mem);
115       return 0;
116     };
117
118   unsigned long cap = cv & (Config::PAGE_SIZE - 1) | (unsigned long)mem;
119
120   return reinterpret_cast<Entry*>(cap);
121 }
122
123 PROTECTED template< typename SPACE >
124 void
125 Obj_space_virt<SPACE>::caps_free()
126 {
127   Mem_space *ms = SPACE::mem_space(this);
128   if (EXPECT_FALSE(!ms || !ms->dir()))
129     return;
130
131   Kmem_alloc *a = Kmem_alloc::allocator();
132   for (Cap_index i = Cap_index(0); i < obj_map_max_address();
133        i += Cap_diff(Obj::Caps_per_page))
134     {
135       Entry *c = get_cap(i);
136       if (!c)
137         continue;
138
139       Address cp = Address(ms->virt_to_phys(Address(c)));
140       assert_kdb (cp != ~0UL);
141       void *cv = (void*)Mem_layout::phys_to_pmem(cp);
142       Obj::remove_cap_page_dbg_info(cv);
143
144       a->q_unaligned_free(SPACE::ram_quota(this), Config::PAGE_SIZE, cv);
145     }
146   ms->dir()->destroy(Virt_addr(Mem_layout::Caps_start),
147                      Virt_addr(Mem_layout::Caps_end-1),
148                      Pdir::Super_level,
149                      Pdir::Depth,
150                      Kmem_alloc::q_allocator(SPACE::ram_quota(this)));
151 }
152
153 //
154 // Utilities for map<Obj_space_virt> and unmap<Obj_space_virt>
155 //
156
157 IMPLEMENT  template< typename SPACE >
158 inline  NEEDS[Obj_space_virt::cap_virt, Obj_space_virt::get_cap]
159 bool __attribute__((__flatten__))
160 Obj_space_virt<SPACE>::v_lookup(V_pfn const &virt, Phys_addr *phys,
161                                    Page_order *size, Attr *attribs)
162 {
163   if (size) *size = Order(0);
164   Entry *cap;
165
166   if (Optimize_local
167       && SPACE::mem_space(this) == Mem_space::current_mem_space(current_cpu()))
168     cap = cap_virt(virt);
169   else
170     cap = get_cap(virt);
171
172   if (EXPECT_FALSE(!cap))
173     {
174       if (size) *size = Order(Obj::Caps_per_page_ld2);
175       return false;
176     }
177
178   if (Optimize_local)
179     {
180       Capability c = Mem_layout::read_special_safe((Capability*)cap);
181
182       if (phys) *phys = c.obj();
183       if (c.valid() && attribs)
184         *attribs = Attr(c.rights());
185       return c.valid();
186     }
187   else
188     {
189       Obj::set_entry(virt, cap);
190       if (phys) *phys = cap->obj();
191       if (cap->valid() && attribs)
192         *attribs = Attr(cap->rights());
193       return cap->valid();
194     }
195 }
196
197 IMPLEMENT template< typename SPACE >
198 inline NEEDS [Obj_space_virt::cap_virt, Obj_space_virt::get_cap]
199 typename Obj_space_virt<SPACE>::Capability __attribute__((__flatten__))
200 Obj_space_virt<SPACE>::lookup(Cap_index virt)
201 {
202   Capability *c;
203   virt &= Cap_index(~(~0UL << Whole_space));
204
205   if (SPACE::mem_space(this) == Mem_space::current_mem_space(current_cpu()))
206     c = reinterpret_cast<Capability*>(cap_virt(virt));
207   else
208     c = get_cap(virt);
209
210   if (EXPECT_FALSE(!c))
211     return Capability(0); // void
212
213   return Mem_layout::read_special_safe(c);
214 }
215
216 PUBLIC template< typename SPACE >
217 inline NEEDS [Obj_space_virt::cap_virt]
218 Kobject_iface *
219 Obj_space_virt<SPACE>::lookup_local(Cap_index virt, L4_fpage::Rights *rights)
220 {
221   virt &= Cap_index(~(~0UL << Whole_space));
222   Capability *c = reinterpret_cast<Capability*>(cap_virt(virt));
223   Capability cap = Mem_layout::read_special_safe(c);
224   if (rights) *rights = L4_fpage::Rights(cap.rights());
225   return cap.obj();
226 }
227
228
229 IMPLEMENT template< typename SPACE >
230 inline NEEDS[<cassert>, Obj_space_virt::cap_virt, Obj_space_virt::get_cap]
231 L4_fpage::Rights __attribute__((__flatten__))
232 Obj_space_virt<SPACE>::v_delete(V_pfn virt, Order size,
233                                    L4_fpage::Rights page_attribs)
234 {
235   (void)size;
236   assert (size == Order(0));
237
238   Entry *c;
239   if (Optimize_local
240       && SPACE::mem_space(this) == Mem_space::current_mem_space(current_cpu()))
241     {
242       c = cap_virt(virt);
243       if (!c)
244         return L4_fpage::Rights(0);
245
246       Capability cap = Mem_layout::read_special_safe((Capability*)c);
247       if (!cap.valid())
248         return L4_fpage::Rights(0);
249     }
250   else
251     c = get_cap(virt);
252
253   if (c && c->valid())
254     {
255       if (page_attribs & L4_fpage::Rights::R())
256         c->invalidate();
257       else
258         c->del_rights(page_attribs & L4_fpage::Rights::CWSD());
259     }
260
261   return L4_fpage::Rights(0);
262 }
263
264 IMPLEMENT  template< typename SPACE >
265 inline NEEDS[Obj_space_virt::cap_virt, Obj_space_virt::caps_alloc,
266              Obj_space_virt::get_cap, "kdb_ke.h"]
267 typename Obj::Insert_result __attribute__((__flatten__))
268 Obj_space_virt<SPACE>::v_insert(Phys_addr phys, V_pfn const &virt, Order size,
269                                 Attr page_attribs)
270 {
271   (void)size;
272   assert (size == Order(0));
273
274   Entry *c;
275
276   if (Optimize_local
277       && SPACE::mem_space(this) == Mem_space::current_mem_space(current_cpu()))
278     {
279       c = cap_virt(virt);
280       if (!c)
281         return Obj::Insert_err_nomem;
282
283       Capability cap;
284       if (!Mem_layout::read_special_safe((Capability*)c, cap)
285           && !caps_alloc(virt))
286         return Obj::Insert_err_nomem;
287     }
288   else
289     {
290       c = get_cap(virt);
291       if (!c && !(c = caps_alloc(virt)))
292         return Obj::Insert_err_nomem;
293       Obj::set_entry(virt, c);
294     }
295
296   if (c->valid())
297     {
298       if (c->obj() == phys)
299         {
300           if (EXPECT_FALSE(c->rights() == page_attribs))
301             return Obj::Insert_warn_exists;
302
303           c->add_rights(page_attribs);
304           return Obj::Insert_warn_attrib_upgrade;
305         }
306       else
307         return Obj::Insert_err_exists;
308     }
309
310   c->set(phys, page_attribs);
311   return Obj::Insert_ok;
312 }
313
314
315 PUBLIC  template< typename SPACE >
316 virtual inline
317 typename Obj_space_virt<SPACE>::V_pfn
318 Obj_space_virt<SPACE>::obj_map_max_address() const
319 {
320   Mword r;
321
322   r = (Mem_layout::Caps_end - Mem_layout::Caps_start) / sizeof(Entry);
323   if (Map_max_address < r)
324     r = Map_max_address;
325
326   return V_pfn(r);
327 }
328
329 // ------------------------------------------------------------------------------
330 IMPLEMENTATION [debug]:
331
332 PUBLIC  template< typename SPACE >
333 typename Obj_space_virt<SPACE>::Entry *
334 Obj_space_virt<SPACE>::jdb_lookup_cap(Cap_index index)
335 { return get_cap(index); }
336