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