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