]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/kmem_alloc.cpp
update
[l4.git] / kernel / fiasco / src / kern / kmem_alloc.cpp
1 INTERFACE:
2
3 #include <auto_quota.h>
4 #include <cxx/slist>
5
6 #include "spin_lock.h"
7 #include "lock_guard.h"
8 #include "initcalls.h"
9
10 class Buddy_alloc;
11 class Mem_region_map_base;
12 class Kip;
13
14 template<typename Q> class Kmem_q_alloc;
15
16 class Kmem_alloc
17 {
18   Kmem_alloc();
19
20 public:
21   typedef Buddy_alloc Alloc;
22 private:
23   typedef Spin_lock<> Lock;
24   static Lock lock;
25   static Alloc *a;
26   static unsigned long _orig_free;
27   static Kmem_alloc *_alloc;
28 };
29
30
31 class Kmem_alloc_reaper : public cxx::S_list_item
32 {
33   size_t (*_reap)(bool desperate);
34
35 private:
36   typedef cxx::S_list_bss<Kmem_alloc_reaper> Reaper_list;
37   static Reaper_list mem_reapers;
38 };
39
40 template<typename Q>
41 class Kmem_q_alloc
42 {
43 public:
44   Kmem_q_alloc(Q *q, Kmem_alloc *a) : _a(a), _q(q) {}
45   bool valid() const { return _a && _q; }
46   void *alloc(unsigned long size) const
47   {
48     Auto_quota<Q> q(_q, size);
49     if (EXPECT_FALSE(!q))
50       return 0;
51
52     void *b;
53     if (EXPECT_FALSE(!(b=_a->unaligned_alloc(size))))
54       return 0;
55
56     q.release();
57     return b;
58   }
59
60   void free(void *block, unsigned long size) const
61   {
62     _a->unaligned_free(size, block);
63     _q->free(size);
64   }
65
66   template<typename V>
67   Phys_mem_addr::Value to_phys(V v) const
68   { return _a->to_phys(v); }
69
70 private:
71   Kmem_alloc *_a;
72   Q *_q;
73 };
74
75
76 IMPLEMENTATION:
77
78 #include <cassert>
79
80 #include "config.h"
81 #include "kdb_ke.h"
82 #include "kip.h"
83 #include "mem_layout.h"
84 #include "mem_region.h"
85 #include "buddy_alloc.h"
86 #include "panic.h"
87
88 static Kmem_alloc::Alloc _a;
89 Kmem_alloc::Alloc *Kmem_alloc::a = &_a;
90 unsigned long Kmem_alloc::_orig_free;
91 Kmem_alloc::Lock Kmem_alloc::lock;
92 Kmem_alloc* Kmem_alloc::_alloc;
93
94 PUBLIC static inline NEEDS[<cassert>]
95 Kmem_alloc *
96 Kmem_alloc::allocator()
97 {
98   assert (_alloc /* uninitialized use of Kmem_alloc */);
99   return _alloc;
100 }
101
102
103 PUBLIC template<typename Q> static inline NEEDS[<cassert>]
104 Kmem_q_alloc<Q>
105 Kmem_alloc::q_allocator(Q *quota)
106 {
107   assert (_alloc /* uninitialized use of Kmem_alloc */);
108   return Kmem_q_alloc<Q>(quota, _alloc);
109 }
110
111 PROTECTED static
112 void
113 Kmem_alloc::allocator(Kmem_alloc *a)
114 {
115   _alloc=a;
116 }
117
118 PUBLIC static FIASCO_INIT
119 void
120 Kmem_alloc::init()
121 {
122   static Kmem_alloc al;
123   Kmem_alloc::allocator(&al);
124 }
125
126 PUBLIC
127 void
128 Kmem_alloc::dump() const
129 { a->dump(); }
130
131 PUBLIC inline NEEDS [Kmem_alloc::unaligned_alloc]
132 void *
133 Kmem_alloc::alloc(size_t o)
134 {
135   return unaligned_alloc(1UL << o);
136 }
137
138
139 PUBLIC inline NEEDS [Kmem_alloc::unaligned_free]
140 void
141 Kmem_alloc::free(size_t o, void *p)
142 {
143   unaligned_free(1UL << o, p);
144 }
145
146 PUBLIC 
147 void *
148 Kmem_alloc::unaligned_alloc(unsigned long size)
149 {
150   assert(size >=8 /*NEW INTERFACE PARANIOIA*/);
151   void* ret;
152
153   {
154     auto guard = lock_guard(lock);
155     ret = a->alloc(size);
156   }
157
158   if (!ret)
159     {
160       Kmem_alloc_reaper::morecore (/* desperate= */ true);
161
162       auto guard = lock_guard(lock);
163       ret = a->alloc(size);
164     }
165
166   return ret;
167 }
168
169 PUBLIC
170 void
171 Kmem_alloc::unaligned_free(unsigned long size, void *page)
172 {
173   assert(size >=8 /*NEW INTERFACE PARANIOIA*/);
174   auto guard = lock_guard(lock);
175   a->free(page, size);
176 }
177
178
179 PRIVATE static FIASCO_INIT
180 unsigned long
181 Kmem_alloc::create_free_map(Kip const *kip, Mem_region_map_base *map)
182 {
183   unsigned long available_size = 0;
184   Mem_desc const *md = kip->mem_descs();
185   Mem_desc const *const md_end = md + kip->num_mem_descs();
186
187   for (; md < md_end; ++md)
188     {
189       if (!md->valid())
190         {
191           const_cast<Mem_desc*>(md)->type(Mem_desc::Undefined);
192           continue;
193         }
194
195       if (md->is_virtual())
196         continue;
197
198       unsigned long s = md->start();
199       unsigned long e = md->end();
200
201       // Sweep out stupid descriptors (that have the end before the start)
202
203       switch (md->type())
204         {
205         case Mem_desc::Conventional:
206           s = (s + Config::PAGE_SIZE - 1) & ~(Config::PAGE_SIZE - 1);
207           e = ((e + 1) & ~(Config::PAGE_SIZE - 1)) - 1;
208           if (e <= s)
209             break;
210           available_size += e - s + 1;
211           if (!map->add(Mem_region(s, e)))
212             panic("Kmem_alloc::create_free_map(): memory map too small");
213           break;
214         case Mem_desc::Reserved:
215         case Mem_desc::Dedicated:
216         case Mem_desc::Shared:
217         case Mem_desc::Arch:
218         case Mem_desc::Bootloader:
219           s = s & ~(Config::PAGE_SIZE - 1);
220           e = ((e + Config::PAGE_SIZE) & ~(Config::PAGE_SIZE - 1)) - 1;
221           if (!map->sub(Mem_region(s, e)))
222             panic("Kmem_alloc::create_free_map(): memory map too small");
223           break;
224         default:
225           break;
226         }
227     }
228
229   return available_size;
230 }
231
232
233 PUBLIC template< typename Q >
234 inline
235 void *
236 Kmem_alloc::q_alloc(Q *quota, size_t order)
237 {
238   Auto_quota<Q> q(quota, 1UL<<order);
239   if (EXPECT_FALSE(!q))
240     return 0;
241
242   void *b = alloc(order);
243   if (EXPECT_FALSE(!b))
244     return 0;
245
246   q.release();
247   return b;
248 }
249
250 PUBLIC template< typename Q >
251 inline
252 void *
253 Kmem_alloc::q_unaligned_alloc(Q *quota, size_t size)
254 {
255   Auto_quota<Q> q(quota, size);
256   if (EXPECT_FALSE(!q))
257     return 0;
258
259   void *b;
260   if (EXPECT_FALSE(!(b=unaligned_alloc(size))))
261     return 0;
262
263   q.release();
264   return b;
265 }
266
267
268 PUBLIC inline NEEDS["mem_layout.h"]
269 void Kmem_alloc::free_phys(size_t s, Address p)
270 {
271   void *va = (void*)Mem_layout::phys_to_pmem(p);
272   if((unsigned long)va != ~0UL)
273     free(s, va);
274 }
275
276 PUBLIC template< typename Q >
277 inline
278 void 
279 Kmem_alloc::q_free_phys(Q *quota, size_t order, Address obj)
280 {
281   free_phys(order, obj);
282   quota->free(1UL<<order);
283 }
284
285 PUBLIC template< typename Q >
286 inline
287 void 
288 Kmem_alloc::q_free(Q *quota, size_t order, void *obj)
289 {
290   free(order, obj);
291   quota->free(1UL<<order);
292 }
293
294 PUBLIC template< typename Q >
295 inline
296 void 
297 Kmem_alloc::q_unaligned_free(Q *quota, size_t size, void *obj)
298 {
299   unaligned_free(size, obj);
300   quota->free(size);
301 }
302
303
304
305 #include "atomic.h"
306
307 Kmem_alloc_reaper::Reaper_list Kmem_alloc_reaper::mem_reapers;
308
309 PUBLIC inline NEEDS["atomic.h"]
310 Kmem_alloc_reaper::Kmem_alloc_reaper(size_t (*reap)(bool desperate))
311   : _reap(reap)
312 {
313   mem_reapers.add(this, mp_cas<cxx::S_list_item*>);
314 }
315
316 PUBLIC static
317 size_t
318 Kmem_alloc_reaper::morecore(bool desperate = false)
319 {
320   size_t freed = 0;
321
322   for (Reaper_list::Const_iterator reaper = mem_reapers.begin();
323        reaper != mem_reapers.end(); ++reaper)
324     {
325       freed += reaper->_reap(desperate);
326     }
327
328   return freed;
329 }