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 #include <l4/cxx/exceptions>
11 #include <l4/cxx/unique_ptr>
12 #include <l4/cxx/l4iostream>
13 
14 #include <l4/re/util/meta>
15 #include <l4/sys/factory>
16 
17 #include <cstdlib>
18 #include <climits>
19 
20 #include "debug.h"
21 #include "alloc.h"
22 #include "dataspace_anon.h"
23 #include "dataspace_noncont.h"
24 #include "dma_space.h"
25 #include "globals.h"
26 #include "page_alloc.h"
27 #include "quota.h"
28 #include "region.h"
29 #include "name_space.h"
30 #include "log.h"
31 #include "sched_proxy.h"
32 
33 static Dbg dbg(Dbg::Warn | Dbg::Server);
34 
35 Moe::Dataspace *
alloc(long size,unsigned long flags,unsigned long align)36 Allocator::alloc(long size, unsigned long flags, unsigned long align)
37 {
38   if (size == 0)
39     throw L4::Bounds_error("stack too small");
40 
41   //L4::cout << "A: \n";
42   Moe::Dataspace *mo;
43   if (flags & L4Re::Mem_alloc::Continuous
44       || flags & L4Re::Mem_alloc::Pinned)
45     {
46       if (flags & L4Re::Mem_alloc::Super_pages)
47         align = cxx::max<unsigned long>(align, L4_SUPERPAGESHIFT);
48       else
49         align = cxx::max<unsigned long>(align, L4_PAGESHIFT);
50 
51       mo = make_obj<Moe::Dataspace_anon>(size, L4Re::Dataspace::F::RWX, align);
52     }
53   else
54     {
55       if (size < 0)
56         throw L4::Bounds_error("invalid size");
57 
58       mo = Moe::Dataspace_noncont::create(qalloc(), size);
59       Obj_list::insert_after(mo, Obj_list::iter(this));
60     }
61 
62   // L4::cout << "A: mo=" << mo << "\n";
63 
64   //L4::cout << "A[" << this << "]: allocated(" << mo << " " << mo->obj_cap() << ")\n";
65   return mo;
66 }
67 
~Allocator()68 Allocator::~Allocator()
69 {
70   assert (Obj_list::in_list(this));
71 
72   // NOTE: the Obj_list iterator must be/is safe according to deletion of the
73   // current or any later element from the list, when deleting the current
74   // element the iterator automatically advances to the next element.
75   auto it = ++Obj_list::iter(this);
76   while (it != Obj_list::Iterator()
77          && Moe::Malloc_container::from_ptr(*it) == qalloc())
78     delete *it;
79 
80   if (qalloc()->quota()->used() > 0)
81     dbg.printf("WARNING: destroyed allocator still holds resources.");
82 
83   // return our quota to the parant
84   qalloc()->reparent(parent_qalloc());
85 }
86 
87 
88 class LLog : public Moe::Log
89 {
90 private:
91   char _tag[32];
92 
93 public:
LLog(char const * t,int l,unsigned char col)94   LLog(char const *t, int l, unsigned char col) : Log()
95   {
96     if (l > 32)
97       l = 32;
98 
99     memcpy(_tag, t, l);
100 
101     set_tag(_tag, l);
102 
103     set_color(col);
104   }
105 
~LLog()106   virtual ~LLog() {}
107 };
108 
109 int
op_create(L4::Factory::Rights,L4::Ipc::Cap<void> & res,long type,L4::Ipc::Varg_list<> && args)110 Allocator::op_create(L4::Factory::Rights, L4::Ipc::Cap<void> &res,
111                      long type, L4::Ipc::Varg_list<> &&args)
112 {
113   L4::Cap<L4::Kobject> ko;
114 
115   switch (type)
116     {
117     case L4Re::Namespace::Protocol:
118         {
119           cxx::unique_ptr<Moe::Name_space> o(make_obj<Moe::Name_space>());
120           ko = object_pool.cap_alloc()->alloc(o.get());
121           ko->dec_refcnt(1);
122           o.release();
123           res = L4::Ipc::make_cap(ko, L4_CAP_FPAGE_RWSD);
124           return L4_EOK;
125         }
126 
127     case L4Re::Rm::Protocol:
128         {
129           cxx::unique_ptr<Region_map> o(make_obj<Region_map>());
130           ko = object_pool.cap_alloc()->alloc(o.get());
131           ko->dec_refcnt(1);
132           o.release();
133           res = L4::Ipc::make_cap(ko, L4_CAP_FPAGE_RWSD);
134           return L4_EOK;
135         }
136 
137     case L4::Factory::Protocol:
138         {
139           L4::Ipc::Varg quota = args.pop_front();
140 
141           if (!quota.is_of_int() || quota.value<long>() <= 0)
142             return -L4_EINVAL;
143           Moe::Quota_guard g(_qalloc.quota(), quota.value<long>());
144           cxx::unique_ptr<Allocator>
145             o(make_obj<Allocator>(quota.value<long>()));
146           ko = object_pool.cap_alloc()->alloc(o.get());
147           ko->dec_refcnt(1);
148           o.release();
149           g.release();
150           res = L4::Ipc::make_cap(ko, L4_CAP_FPAGE_RWSD);
151 
152           return L4_EOK;
153         }
154 
155     case L4_PROTO_LOG:
156         {
157           L4::Ipc::Varg tag = args.pop_front();
158 
159           if (!tag.is_of<char const *>())
160             return -L4_EINVAL;
161 
162           L4::Ipc::Varg col = args.pop_front();
163 
164           int color;
165           if (col.is_of<char const *>())
166             color = LLog::color_value(cxx::String(col.value<char const *>(),
167                                       col.length() - 1));
168           else if (col.is_of_int())
169             color = col.value<l4_mword_t>();
170           else
171             color = 7;
172 
173           cxx::unique_ptr<Moe::Log> l(make_obj<LLog>(tag.value<char const *>(),
174                                                      tag.length() - 1, color));
175           ko = object_pool.cap_alloc()->alloc(l.get());
176           ko->dec_refcnt(1);
177           l.release();
178           res = L4::Ipc::make_cap(ko, L4_CAP_FPAGE_RWSD);
179           return L4_EOK;
180         }
181 
182     case L4::Scheduler::Protocol:
183         {
184           if (!_sched_prio_limit)
185             return -L4_ENODEV;
186 
187           L4::Ipc::Varg p_max  = args.pop_front(),
188                         p_base = args.pop_front(),
189                         cpus   = args.pop_front();
190 
191           if (!p_max.is_of_int() || !p_base.is_of_int())
192             return -L4_EINVAL;
193 
194           if (p_max.value<l4_mword_t>() > _sched_prio_limit
195               || p_base.value<l4_mword_t>() > _sched_prio_limit)
196             return -L4_ERANGE;
197 
198           if (p_max.value<l4_mword_t>() <= p_base.value<l4_mword_t>())
199             return -L4_EINVAL;
200 
201           l4_umword_t cpu_mask = ~0UL;
202 
203           if (!cpus.is_of<void>() && cpus.is_of_int())
204             cpu_mask = cpus.value<l4_umword_t>();
205 
206           cxx::unique_ptr<Sched_proxy> o(make_obj<Sched_proxy>());
207           o->set_prio(p_base.value<l4_mword_t>(), p_max.value<l4_mword_t>());
208           o->restrict_cpus(cpu_mask);
209           ko = object_pool.cap_alloc()->alloc(o.get());
210           ko->dec_refcnt(1);
211           o.release();
212           res = L4::Ipc::make_cap(ko, L4_CAP_FPAGE_RWSD);
213           return L4_EOK;
214         }
215 
216     case L4Re::Dataspace::Protocol:
217         {
218           L4::Ipc::Varg size  = args.pop_front(),
219                         flags = args.pop_front(),
220                         align = args.pop_front();
221 
222           if (!size.is_of_int())
223             return -L4_EINVAL;
224 
225           // L4::cout << "MEM: alloc ... " << size.value<l4_mword_t>() << "; " << flags.value<l4_umword_t>() << "\n";
226           cxx::unique_ptr<Moe::Dataspace> mo(alloc(size.value<l4_mword_t>(),
227                 flags.is_of_int() ? flags.value<l4_umword_t>() : 0,
228                 align.is_of_int() ? align.value<l4_umword_t>() : 0));
229 
230           // L4::cout << "MO=" << mo.get() << "\n";
231           ko = object_pool.cap_alloc()->alloc(mo.get());
232           ko->dec_refcnt(1);
233           // L4::cout << "MO_CAP=" << mo->obj_cap() << "\n";
234           res = L4::Ipc::make_cap(ko, L4_CAP_FPAGE_RWSD);
235           mo.release();
236           return L4_EOK;
237         }
238 
239     case L4Re::Dma_space::Protocol:
240         {
241           cxx::unique_ptr<Moe::Dma_space> o(make_obj<Moe::Dma_space>());
242           ko = object_pool.cap_alloc()->alloc(o.get());
243           ko->dec_refcnt(1);
244           res = L4::Ipc::make_cap(ko, L4_CAP_FPAGE_RWSD);
245           o.release();
246           return L4_EOK;
247         }
248 
249     default:
250       return -L4_ENODEV;
251     }
252 }
253 
254 #ifndef NDEBUG
255 long
op_debug(L4Re::Debug_obj::Rights,unsigned long)256 Allocator::op_debug(L4Re::Debug_obj::Rights, unsigned long)
257 {
258   Dbg out(Dbg::Info, "mem_alloc");
259   if (_qalloc.quota()->limit() == (size_t)~0)
260     out.printf("quota: no limit, used: %zu bytes (%zu MB)\n",
261                _qalloc.quota()->used(), _qalloc.quota()->used() / (1<<20));
262   else
263     out.printf("quota: limit: %zu bytes (%zu MB), used: %zu bytes (%zu MB), avail: %zu bytes (%zu MB)\n",
264                _qalloc.quota()->limit(), _qalloc.quota()->limit() / (1<<20),
265                _qalloc.quota()->used(),  _qalloc.quota()->used()  / (1<<20),
266                _qalloc.quota()->limit() - _qalloc.quota()->used(),
267                (_qalloc.quota()->limit() - _qalloc.quota()->used()) / (1<<20));
268   out.printf("global: avail: %lu bytes (%lu MB)\n",
269              Single_page_alloc_base::_avail(),
270              Single_page_alloc_base::_avail() / (1<<20));
271   out.printf("global physical free list:\n");
272   Single_page_alloc_base::_dump_free(out);
273   return L4_EOK;
274 }
275 #endif
276 
277 static Allocator *_root_alloc;
278 
279 Allocator *
root_allocator()280 Allocator::root_allocator()
281 {
282   if (_root_alloc)
283     return _root_alloc;
284 
285   _root_alloc = Moe::Moe_alloc::allocator()->make_obj<Allocator>(~0, 300000);
286   object_pool.life.push_front(_root_alloc);
287   return _root_alloc;
288 }
289