]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/factory.cpp
update
[l4.git] / kernel / fiasco / src / kern / factory.cpp
1 INTERFACE:
2
3 #include "ram_quota.h"
4 #include "kobject_helper.h"
5
6 class Factory : public Ram_quota, public Kobject_h<Factory>
7 {
8   FIASCO_DECLARE_KOBJ();
9
10 private:
11   typedef slab_cache_anon Self_alloc;
12 };
13
14 //---------------------------------------------------------------------------
15 IMPLEMENTATION:
16
17 #include "ipc_gate.h"
18 #include "kmem_slab.h"
19 #include "task.h"
20 #include "thread_object.h"
21 #include "static_init.h"
22 #include "l4_buf_iter.h"
23 #include "l4_types.h"
24 #include "u_semaphore.h"
25 #include "irq.h"
26 #include "map_util.h"
27 #include "logdefs.h"
28 #include "entry_frame.h"
29
30 static Factory _root_factory INIT_PRIORITY(ROOT_FACTORY_INIT_PRIO);
31 FIASCO_DEFINE_KOBJ(Factory);
32
33 PUBLIC inline
34 Factory::Factory()
35   : Ram_quota()
36 {}
37
38 PRIVATE inline
39 Factory::Factory(Ram_quota *q, unsigned long max)
40   : Ram_quota(q, max)
41 {}
42
43
44 static Kmem_slab_t<Factory> _factory_allocator("Factory");
45
46 PRIVATE static
47 Factory::Self_alloc *
48 Factory::allocator()
49 { return &_factory_allocator; }
50
51 PUBLIC static inline
52 Factory *
53 Factory::root()
54 { return static_cast<Factory*>(Ram_quota::root); }
55
56
57 PRIVATE
58 Factory *
59 Factory::create_factory(unsigned long max)
60 {
61   void *nq;
62   if (alloc(sizeof(Factory) + max) && (nq = allocator()->alloc()))
63     return new (nq) Factory(this, max);
64
65   return 0;
66 }
67
68 PUBLIC
69 void Factory::operator delete (void *_f)
70 {
71   Factory *f = (Factory*)_f;
72   LOG_TRACE("Factory delete", "fa del", ::current(), 0, {});
73
74   if (!f->parent())
75     return;
76
77   Ram_quota *p = f->parent();
78   if (p)
79     p->free(sizeof(Factory) + f->limit());
80
81   allocator()->free(f);
82 }
83
84 PRIVATE
85 L4_msg_tag
86 Factory::map_obj(Kobject_iface *o, Mword cap, Space *c_space,
87                  Obj_space *o_space)
88 {
89   switch (Mword(o))
90     {
91     case 0:               return commit_result(-L4_err::ENomem);
92     case -L4_err::EInval: return commit_result(-L4_err::EInval);
93     case -L4_err::EPerm:  return commit_result(-L4_err::EPerm);
94     default:              break;
95     };
96
97   Reap_list rl;
98
99   if (!map(o, o_space, c_space, cap, rl.list()))
100     {
101       delete o;
102       // FIXME: reap stuff if needed
103       return commit_result(-L4_err::ENomem);
104     }
105
106   // FIXME: reap stuff if needed
107   return commit_result(0, 0, 1);
108 }
109
110
111
112 PRIVATE inline NOEXPORT
113 Kobject_iface *
114 Factory::new_factory(Utcb const *u)
115 {
116   // XXX: should check for type tag in new call
117   return create_factory(u->values[2]);
118 }
119
120
121 PRIVATE inline NOEXPORT
122 Kobject_iface *
123 Factory::new_task(Utcb const *u)
124 {
125   L4_fpage utcb_area(0);
126   // XXX: should check for type tag in new call
127   utcb_area = L4_fpage(u->values[2]);
128
129   Task *new_t = Task::create(Space::Default_factory(), this, utcb_area);
130
131   if (!new_t)
132     return 0;
133
134   if (!new_t->valid() || !new_t->initialize())
135     {
136       delete new_t;
137       return 0;
138     }
139
140   return new_t;
141 }
142
143 PRIVATE inline NOEXPORT
144 Kobject_iface *
145 Factory::new_thread(Utcb const *)
146 {
147   Thread_object *t = new (this) Thread_object();
148   return t;
149 }
150
151 PRIVATE inline NOEXPORT
152 Kobject_iface *
153 Factory::new_gate(L4_msg_tag const &tag, Utcb const *utcb, Obj_space *o_space)
154 {
155   L4_snd_item_iter snd_items(utcb, tag.words());
156   Thread *thread = 0;
157
158   if (tag.items() && snd_items.next())
159     {
160       L4_fpage bind_thread(snd_items.get()->d);
161       if (EXPECT_FALSE(!bind_thread.is_objpage()))
162         return reinterpret_cast<Kobject_iface*>(-L4_err::EInval);
163
164       unsigned char thread_rights = 0;
165       thread = Kobject::dcast<Thread_object*>(o_space->lookup_local(bind_thread.obj_index(), &thread_rights));
166
167       if (EXPECT_FALSE(!(thread_rights & L4_fpage::W)))
168         return reinterpret_cast<Kobject_iface*>(-L4_err::EPerm);
169     }
170 #if 0
171   if (!thread)
172     return reinterpret_cast<Kobject_iface*>(-L4_err::EInval);
173 #endif
174   // should check type tag of varg
175   return static_cast<Ipc_gate_ctl*>(Ipc_gate::create(this, thread, utcb->values[2]));
176 }
177
178
179 PRIVATE inline NOEXPORT
180 Kobject_iface *
181 Factory::new_semaphore(Utcb const *)
182 {
183   return U_semaphore::alloc(this);
184 }
185
186 PRIVATE inline NOEXPORT
187 Kobject_iface *
188 Factory::new_irq(unsigned w, Utcb const *utcb)
189 {
190   if (w >= 3 && utcb->values[2])
191     return Irq::allocate<Irq_muxer>(this);
192   else
193     return Irq::allocate<Irq_sender>(this);
194 }
195
196 PUBLIC
197 L4_msg_tag
198 Factory::kinvoke(L4_obj_ref ref, Mword rights, Syscall_frame *f,
199                  Utcb const *utcb, Utcb *)
200 {
201   register Context *const c_thread = ::current();
202   register Space *const c_space = c_thread->space();
203   register Obj_space *const o_space = c_space->obj_space();
204
205   if (EXPECT_FALSE(f->tag().proto() != L4_msg_tag::Label_factory))
206     return commit_result(-L4_err::EBadproto);
207
208   if (EXPECT_FALSE(!(rights & L4_fpage::W)))
209     return commit_result(-L4_err::EPerm);
210
211   if (EXPECT_FALSE(!ref.have_recv()))
212     return commit_result(0);
213
214   if (f->tag().words() < 1)
215     return commit_result(-L4_err::EInval);
216
217   L4_fpage buffer(0);
218
219     {
220       L4_buf_iter buf(utcb, utcb->buf_desc.obj());
221       L4_buf_iter::Item const *const b = buf.get();
222       if (EXPECT_FALSE(b->b.is_void()
223             || b->b.type() != L4_msg_item::Map))
224         return commit_error(utcb, L4_error(L4_error::Overflow, L4_error::Rcv));
225
226       buffer = L4_fpage(b->d);
227     }
228
229   if (EXPECT_FALSE(!buffer.is_objpage()))
230     return commit_error(utcb, L4_error(L4_error::Overflow, L4_error::Rcv));
231
232   Kobject_iface *new_o;
233
234   switch ((long)utcb->values[0])
235     {
236     case 0:  // new IPC Gate
237       new_o = new_gate(f->tag(), utcb, o_space);
238       break;
239
240     case L4_msg_tag::Label_factory:
241       new_o = new_factory(utcb);
242       break;
243
244     case L4_msg_tag::Label_task:
245       new_o =  new_task(utcb);
246       break;
247
248     case L4_msg_tag::Label_thread:
249       new_o = new_thread(utcb);
250       break;
251
252     case L4_msg_tag::Label_semaphore:
253       new_o = new_semaphore(utcb);
254       break;
255
256     case L4_msg_tag::Label_irq:
257       new_o = new_irq(f->tag().words(), utcb);
258       break;
259
260     case L4_msg_tag::Label_vm:
261       new_o = new_vm(utcb);
262       break;
263
264     default:
265       return commit_result(-L4_err::ENodev);
266     }
267
268   LOG_TRACE("Kobject create", "new", ::current(), __factory_log_fmt,
269     Log_entry *le = tbe->payload<Log_entry>();
270     le->op = utcb->values[0];
271     le->buffer = buffer.obj_index();
272     le->id = dbg_info()->dbg_id();
273     le->ram = current();
274     le->newo = new_o ? new_o->dbg_info()->dbg_id() : ~0);
275
276   return map_obj(new_o, buffer.obj_index(), c_space, o_space);
277
278 }
279
280
281 //----------------------------------------------------------------------------
282 IMPLEMENTATION [svm || vmx]:
283
284 #include "vm_factory.h"
285
286 PRIVATE inline NOEXPORT
287 Kobject_iface *
288 Factory::new_vm(Utcb const *)
289 {
290   Vm *new_t = Vm_factory::create(this);
291
292   if (!new_t)
293     return 0;
294
295   if (!new_t->valid() || !new_t->initialize())
296     {
297       delete new_t;
298       return 0;
299     }
300
301   return new_t;
302 }
303
304 IMPLEMENTATION [tz]:
305
306 #include "vm.h"
307
308 PRIVATE inline NOEXPORT
309 Kobject_iface *
310 Factory::new_vm(Utcb const *)
311 {
312   return Vm::create(this);
313 }
314
315 //----------------------------------------------------------------------------
316 IMPLEMENTATION [!svm && !tz && !vmx]:
317
318 PRIVATE inline NOEXPORT
319 Kobject_iface *
320 Factory::new_vm(Utcb const *)
321 { return (Kobject_iface*)(-L4_err::EInval); }
322
323 // ------------------------------------------------------------------------
324 INTERFACE [debug]:
325
326 #include "tb_entry.h"
327
328 EXTENSION class Factory
329 {
330 private:
331   struct Log_entry
332   {
333     Smword op;
334     Mword buffer;
335     Mword id;
336     Mword ram;
337     Mword newo;
338   };
339   static unsigned log_fmt(Tb_entry *, int, char *) asm ("__factory_log_fmt");
340 };
341
342 // ------------------------------------------------------------------------
343 IMPLEMENTATION [debug]:
344
345 IMPLEMENT
346 unsigned
347 Factory::log_fmt(Tb_entry *e, int maxlen, char *buf)
348 {
349   static char const *const ops[] =
350   { /*   0 */ "gate", "irq", 0, 0, 0, 0, 0, 0,
351     /*  -8 */ 0, 0, 0, "task", "thread", 0, 0, "factory",
352     /* -16 */ "vm", 0, 0, 0, "sem" }; 
353   Log_entry *le = e->payload<Log_entry>();
354   char const *op = -le->op <= (int)(sizeof(ops)/sizeof(ops[0]))
355     ? ops[-le->op] : "invalid op";
356   if (!op)
357     op = "(nan)";
358
359   return snprintf(buf, maxlen, "factory=%lx [%s] new=%lx cap=[C:%lx] ram=%lx", le->id, op, le->newo, le->buffer, le->ram);
360 }