3 #include "fiasco_defs.h"
5 #include "slab_cache.h"
6 #include "kobject_helper.h"
8 class Factory : public Ram_quota, public Kobject_h<Factory>
10 FIASCO_DECLARE_KOBJ();
13 typedef Slab_cache Self_alloc;
16 //---------------------------------------------------------------------------
20 #include "kmem_slab.h"
22 #include "thread_object.h"
23 #include "static_init.h"
24 #include "l4_buf_iter.h"
29 #include "entry_frame.h"
31 static Factory _root_factory INIT_PRIORITY(ROOT_FACTORY_INIT_PRIO);
32 FIASCO_DEFINE_KOBJ(Factory);
40 Factory::Factory(Ram_quota *q, unsigned long max)
45 static Kmem_slab_t<Factory> _factory_allocator("Factory");
50 { return &_factory_allocator; }
55 { return nonull_static_cast<Factory*>(Ram_quota::root); }
60 Factory::create_factory(unsigned long max)
62 Auto_quota<Ram_quota> q(this, sizeof(Factory) + max);
66 void *nq = allocator()->alloc();
67 if (EXPECT_FALSE(!nq))
71 return new (nq) Factory(this, max);
75 void Factory::operator delete (void *_f)
77 Factory *f = (Factory*)_f;
78 LOG_TRACE("Factory delete", "fa del", ::current(), Tb_entry_empty, {});
83 Ram_quota *p = f->parent();
87 p->free(sizeof(Factory) + f->limit());
92 Factory::map_obj(Kobject_iface *o, Cap_index cap, Task *c_space,
93 Obj_space *o_space, Utcb const *utcb)
95 // must be before the lock guard
98 auto space_lock_guard = lock_guard_dont_lock(c_space->existence_lock);
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))
106 return commit_error(utcb, L4_error(L4_error::Overflow, L4_error::Rcv));
109 if (!map(o, o_space, c_space, cap, rl.list()))
112 return commit_result(-L4_err::ENomem);
115 // return a tag with one typed item for the returned capability
116 return commit_result(0, 0, 1);
121 PRIVATE inline NOEXPORT
123 Factory::new_factory(Utcb const *u, int *)
125 return create_factory(u->values[2]);
129 PRIVATE inline NOEXPORT
131 Factory::new_task(Utcb const *u, int *)
133 L4_fpage utcb_area(0);
134 utcb_area = L4_fpage(u->values[2]);
136 if (Task *new_t = Task::create<Task>(this, utcb_area))
142 PRIVATE inline NOEXPORT
144 Factory::new_thread(Utcb const *, int *)
145 { return new (this) Thread_object(); }
147 PRIVATE inline NOEXPORT
149 Factory::new_gate(L4_msg_tag const &tag, Utcb const *utcb, Obj_space *o_space,
152 L4_snd_item_iter snd_items(utcb, tag.words());
155 if (tag.items() && snd_items.next())
157 L4_fpage bind_thread(snd_items.get()->d);
158 *err = L4_err::EInval;
159 if (EXPECT_FALSE(!bind_thread.is_objpage()))
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));
165 *err = L4_err::EPerm;
166 if (EXPECT_FALSE(!(thread_rights & L4_fpage::Rights::W())))
170 *err = L4_err::ENomem;
171 return static_cast<Ipc_gate_ctl*>(Ipc_gate::create(this, thread, utcb->values[2]));
174 PRIVATE inline NOEXPORT
176 Factory::new_irq(unsigned w, Utcb const *utcb, int *)
178 if (w >= 3 && utcb->values[2])
179 return Irq::allocate<Irq_muxer>(this);
181 return Irq::allocate<Irq_sender>(this);
186 Factory::kinvoke(L4_obj_ref ref, L4_fpage::Rights rights, Syscall_frame *f,
187 Utcb const *utcb, Utcb *)
189 register Context *const c_thread = ::current();
190 register Task *const c_space = static_cast<Task*>(c_thread->space());
192 if (EXPECT_FALSE(f->tag().proto() != L4_msg_tag::Label_factory))
193 return commit_result(-L4_err::EBadproto);
195 if (EXPECT_FALSE(!(rights & L4_fpage::Rights::CS())))
196 return commit_result(-L4_err::EPerm);
198 if (EXPECT_FALSE(!ref.have_recv()))
199 return commit_result(0);
201 if (f->tag().words() < 1)
202 return commit_result(-L4_err::EInval);
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));
213 buffer = L4_fpage(b->d);
216 if (EXPECT_FALSE(!buffer.is_objpage()))
217 return commit_error(utcb, L4_error(L4_error::Overflow, L4_error::Rcv));
219 Kobject_iface *new_o;
220 int err = L4_err::ENomem;
222 auto cpu_lock_guard = lock_guard<Lock_guard_inverse_policy>(cpu_lock);
224 switch ((long)utcb->values[0])
226 case 0: // new IPC Gate
227 new_o = new_gate(f->tag(), utcb, c_space, &err);
230 case L4_msg_tag::Label_factory:
231 new_o = new_factory(utcb, &err);
234 case L4_msg_tag::Label_task:
235 new_o = new_task(utcb, &err);
238 case L4_msg_tag::Label_thread:
239 new_o = new_thread(utcb, &err);
242 case L4_msg_tag::Label_irq:
243 new_o = new_irq(f->tag().words(), utcb, &err);
246 case L4_msg_tag::Label_vm:
247 new_o = new_vm(utcb, &err);
251 return commit_result(-L4_err::ENodev);
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();
259 l->newo = new_o ? new_o->dbg_info()->dbg_id() : ~0);
262 return map_obj(new_o, buffer.obj_index(), c_space, c_space, utcb);
264 return commit_result(-err);
269 //----------------------------------------------------------------------------
270 IMPLEMENTATION [svm || vmx || arm_em_tz]:
272 #include "vm_factory.h"
275 PRIVATE inline NOEXPORT
277 Factory::new_vm(Utcb const *, int *err)
279 if (Vm *new_t = Vm_factory::create(this, err))
285 //----------------------------------------------------------------------------
286 IMPLEMENTATION [!svm && !vmx && !arm_em_tz]:
288 PRIVATE inline NOEXPORT
290 Factory::new_vm(Utcb const *, int *err)
292 *err = L4_err::ENodev;
296 // ------------------------------------------------------------------------
299 #include "tb_entry.h"
301 EXTENSION class Factory
304 struct Log_entry : public Tb_entry
311 void print(String_buffer *buf) const;
315 // ------------------------------------------------------------------------
316 IMPLEMENTATION [debug]:
318 #include "string_buffer.h"
322 Factory::Log_entry::print(String_buffer *buf) const
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";
333 buf->printf("factory=%lx [%s] new=%lx cap=[C:%lx] ram=%lx",
334 id, _op, newo, cxx::int_value<Cap_index>(buffer), ram);