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