]> rtime.felk.cvut.cz Git - l4.git/blobdiff - kernel/fiasco/src/kern/factory.cpp
update
[l4.git] / kernel / fiasco / src / kern / factory.cpp
index 92c1469acd9c02ae8256427a393cb1c05db63c6a..2ff5451efffd0db398d3fbec3735b905f12262a2 100644 (file)
@@ -1,14 +1,16 @@
 INTERFACE:
 
+#include "fiasco_defs.h"
 #include "ram_quota.h"
+#include "slab_cache.h"
 #include "kobject_helper.h"
 
-class Factory : public Ram_quota, public Kobject_h<Factory>, public Kobject
+class Factory : public Ram_quota, public Kobject_h<Factory>
 {
   FIASCO_DECLARE_KOBJ();
 
 private:
-  typedef slab_cache_anon Self_alloc;
+  typedef Slab_cache Self_alloc;
 };
 
 //---------------------------------------------------------------------------
@@ -17,11 +19,10 @@ IMPLEMENTATION:
 #include "ipc_gate.h"
 #include "kmem_slab.h"
 #include "task.h"
-#include "thread.h"
+#include "thread_object.h"
 #include "static_init.h"
 #include "l4_buf_iter.h"
 #include "l4_types.h"
-#include "u_semaphore.h"
 #include "irq.h"
 #include "map_util.h"
 #include "logdefs.h"
@@ -40,72 +41,66 @@ Factory::Factory(Ram_quota *q, unsigned long max)
   : Ram_quota(q, max)
 {}
 
-PRIVATE static inline NOEXPORT NEEDS["kmem_slab.h"]
+
+static Kmem_slab_t<Factory> _factory_allocator("Factory");
+
+PRIVATE static
 Factory::Self_alloc *
 Factory::allocator()
-{
-  static Self_alloc* slabs =
-    new Kmem_slab_simple (sizeof (Factory), sizeof (Mword), "Factory");
-
-  return slabs;
-}
+{ return &_factory_allocator; }
 
 PUBLIC static inline
-Factory *
+Factory * FIASCO_PURE
 Factory::root()
-{ return static_cast<Factory*>(Ram_quota::root); }
+{ return nonull_static_cast<Factory*>(Ram_quota::root); }
 
 
 PRIVATE
 Factory *
 Factory::create_factory(unsigned long max)
 {
-  void *nq;
-  if (alloc(sizeof(Factory) + max) && (nq = allocator()->alloc()))
-    return new (nq) Factory(this, max);
+  Auto_quota<Ram_quota> q(this, sizeof(Factory) + max);
+  if (EXPECT_FALSE(!q))
+    return 0;
 
-  return 0;
+  void *nq = allocator()->alloc();
+  if (EXPECT_FALSE(!nq))
+    return 0;
+
+  q.release();
+  return new (nq) Factory(this, max);
 }
 
 PUBLIC
 void Factory::operator delete (void *_f)
 {
   Factory *f = (Factory*)_f;
-  LOG_TRACE("Factory delete", "fa del", ::current(), 0, {});
+  LOG_TRACE("Factory delete", "fa del", ::current(), Tb_entry_empty, {});
 
   if (!f->parent())
     return;
 
   Ram_quota *p = f->parent();
-  if (p)
-    p->free(sizeof(Factory) + f->limit());
 
   allocator()->free(f);
+  if (p)
+    p->free(sizeof(Factory) + f->limit());
 }
 
 PRIVATE
 L4_msg_tag
-Factory::map_obj(Kobject_iface *o, Mword cap, Space *c_space,
+Factory::map_obj(Kobject_iface *o, Cap_index cap, Space *c_space,
                  Obj_space *o_space)
 {
-  switch (Mword(o))
-    {
-    case 0:               return commit_result(-L4_err::ENomem);
-    case -L4_err::EInval: return commit_result(-L4_err::EInval);
-    case -L4_err::EPerm:  return commit_result(-L4_err::EPerm);
-    default:              break;
-    };
-
   Reap_list rl;
 
   if (!map(o, o_space, c_space, cap, rl.list()))
     {
       delete o;
-      // FIXME: reap stuff if needed
       return commit_result(-L4_err::ENomem);
     }
 
-  // FIXME: reap stuff if needed
+  // return a tag with one typed item for the returned capability
   return commit_result(0, 0, 1);
 }
 
@@ -113,7 +108,7 @@ Factory::map_obj(Kobject_iface *o, Mword cap, Space *c_space,
 
 PRIVATE inline NOEXPORT
 Kobject_iface *
-Factory::new_factory(Utcb const *u)
+Factory::new_factory(Utcb const *u, int *)
 {
   // XXX: should check for type tag in new call
   return create_factory(u->values[2]);
@@ -122,37 +117,27 @@ Factory::new_factory(Utcb const *u)
 
 PRIVATE inline NOEXPORT
 Kobject_iface *
-Factory::new_task(Utcb const *u)
+Factory::new_task(Utcb const *u, int *)
 {
   L4_fpage utcb_area(0);
   // XXX: should check for type tag in new call
   utcb_area = L4_fpage(u->values[2]);
 
-  Task *new_t = Task::create(Space::Default_factory(), this, utcb_area);
-
-  if (!new_t)
-    return 0;
-
-  if (new_t->state() != Task::Ready || !new_t->initialize())
-    {
-      delete new_t;
-      return 0;
-    }
+  if (Task *new_t = Task::create<Task>(this, utcb_area))
+    return new_t;
 
-  return new_t;
+  return 0;
 }
 
 PRIVATE inline NOEXPORT
 Kobject_iface *
-Factory::new_thread(Utcb const *)
-{
-  Thread *t = new (this) Thread();
-  return t;
-}
+Factory::new_thread(Utcb const *, int *)
+{ return new (this) Thread_object(); }
 
 PRIVATE inline NOEXPORT
 Kobject_iface *
-Factory::new_gate(L4_msg_tag const &tag, Utcb const *utcb, Obj_space *o_space)
+Factory::new_gate(L4_msg_tag const &tag, Utcb const *utcb, Obj_space *o_space,
+                  int *err)
 {
   L4_snd_item_iter snd_items(utcb, tag.words());
   Thread *thread = 0;
@@ -160,53 +145,48 @@ Factory::new_gate(L4_msg_tag const &tag, Utcb const *utcb, Obj_space *o_space)
   if (tag.items() && snd_items.next())
     {
       L4_fpage bind_thread(snd_items.get()->d);
+      *err = L4_err::EInval;
       if (EXPECT_FALSE(!bind_thread.is_objpage()))
-       return reinterpret_cast<Kobject_iface*>(-L4_err::EInval);
+       return 0;
 
-      unsigned char thread_rights = 0;
-      thread = Kobject::dcast<Thread*>(o_space->lookup_local(bind_thread.obj_index(), &thread_rights));
+      L4_fpage::Rights thread_rights = L4_fpage::Rights(0);
+      thread = Kobject::dcast<Thread_object*>(o_space->lookup_local(bind_thread.obj_index(), &thread_rights));
 
-      if (EXPECT_FALSE(!(thread_rights & L4_fpage::W)))
-       return reinterpret_cast<Kobject_iface*>(-L4_err::EPerm);
+      *err = L4_err::EPerm;
+      if (EXPECT_FALSE(!(thread_rights & L4_fpage::Rights::W())))
+       return 0;
     }
 #if 0
   if (!thread)
     return reinterpret_cast<Kobject_iface*>(-L4_err::EInval);
 #endif
   // should check type tag of varg
+  *err = L4_err::ENomem;
   return static_cast<Ipc_gate_ctl*>(Ipc_gate::create(this, thread, utcb->values[2]));
 }
 
-
 PRIVATE inline NOEXPORT
 Kobject_iface *
-Factory::new_semaphore(Utcb const *)
+Factory::new_irq(unsigned w, Utcb const *utcb, int *)
 {
-  return U_semaphore::alloc(this);
+  if (w >= 3 && utcb->values[2])
+    return Irq::allocate<Irq_muxer>(this);
+  else
+    return Irq::allocate<Irq_sender>(this);
 }
 
-PRIVATE inline NOEXPORT
-Kobject_iface *
-Factory::new_irq(Utcb const *)
-{
-  Irq *i = Irq::allocate(this);
-  return i;
-}
-
-
 PUBLIC
 L4_msg_tag
-Factory::kinvoke(L4_obj_ref ref, Mword rights, Syscall_frame *f,
+Factory::kinvoke(L4_obj_ref ref, L4_fpage::Rights rights, Syscall_frame *f,
                  Utcb const *utcb, Utcb *)
 {
   register Context *const c_thread = ::current();
-  register Space *const c_space = c_thread->space();
-  register Obj_space *const o_space = c_space->obj_space();
+  register Task *const c_space = static_cast<Task*>(c_thread->space());
 
   if (EXPECT_FALSE(f->tag().proto() != L4_msg_tag::Label_factory))
     return commit_result(-L4_err::EBadproto);
 
-  if (EXPECT_FALSE(!(rights & L4_fpage::W)))
+  if (EXPECT_FALSE(!(rights & L4_fpage::Rights::CS())))
     return commit_result(-L4_err::EPerm);
 
   if (EXPECT_FALSE(!ref.have_recv()))
@@ -231,96 +211,90 @@ Factory::kinvoke(L4_obj_ref ref, Mword rights, Syscall_frame *f,
     return commit_error(utcb, L4_error(L4_error::Overflow, L4_error::Rcv));
 
   Kobject_iface *new_o;
+  int err = L4_err::ENomem;
+
+  Lock_guard<decltype(c_space->existence_lock)> space_lock_guard;
+
+  // We take the existence_lock for syncronizing maps...
+  // This is kind of coarse grained
+  // try_lock fails if the lock is neither locked nor unlocked
+  if (!space_lock_guard.check_and_lock(&c_space->existence_lock))
+    return commit_error(utcb, L4_error(L4_error::Overflow, L4_error::Rcv));
+
+  Lock_guard<Cpu_lock, Lock_guard_inverse_policy> cpu_lock_guard(&cpu_lock);
 
   switch ((long)utcb->values[0])
     {
     case 0:  // new IPC Gate
-      new_o = new_gate(f->tag(), utcb, o_space);
+      new_o = new_gate(f->tag(), utcb, c_space, &err);
       break;
 
     case L4_msg_tag::Label_factory:
-      new_o = new_factory(utcb);
+      new_o = new_factory(utcb, &err);
       break;
 
     case L4_msg_tag::Label_task:
-      new_o =  new_task(utcb);
+      new_o =  new_task(utcb, &err);
       break;
 
     case L4_msg_tag::Label_thread:
-      new_o = new_thread(utcb);
-      break;
-
-    case L4_msg_tag::Label_semaphore:
-      new_o = new_semaphore(utcb);
+      new_o = new_thread(utcb, &err);
       break;
 
     case L4_msg_tag::Label_irq:
-      new_o = new_irq(utcb);
+      new_o = new_irq(f->tag().words(), utcb, &err);
       break;
 
     case L4_msg_tag::Label_vm:
-      new_o = new_vm(utcb);
+      new_o = new_vm(utcb, &err);
       break;
 
     default:
       return commit_result(-L4_err::ENodev);
     }
 
-  LOG_TRACE("Kobject create", "new", ::current(), __factory_log_fmt,
-    Log_entry *le = tbe->payload<Log_entry>();
-    le->op = utcb->values[0];
-    le->buffer = buffer.obj_index();
-    le->id = dbg_id();
-    le->ram = current();
-    le->newo = new_o ? new_o->dbg_info()->dbg_id() : ~0);
+  LOG_TRACE("Kobject create", "new", ::current(), Log_entry,
+    l->op = utcb->values[0];
+    l->buffer = buffer.obj_index();
+    l->id = dbg_info()->dbg_id();
+    l->ram = current();
+    l->newo = new_o ? new_o->dbg_info()->dbg_id() : ~0);
 
-  return map_obj(new_o, buffer.obj_index(), c_space, o_space);
+  if (new_o)
+    return map_obj(new_o, buffer.obj_index(), c_space, c_space);
+  else
+    return commit_result(-err);
 
 }
 
 
 //----------------------------------------------------------------------------
-IMPLEMENTATION [svm || vmx]:
+IMPLEMENTATION [svm || vmx || arm_em_tz]:
 
 #include "vm_factory.h"
+#include "vm.h"
 
 PRIVATE inline NOEXPORT
 Kobject_iface *
-Factory::new_vm(Utcb const *)
+Factory::new_vm(Utcb const *, int *err)
 {
-  Vm *new_t = Vm_factory::create(this);
-
-  if (!new_t)
-    return 0;
+  if (Vm *new_t = Vm_factory::create(this, err))
+    return new_t;
 
-  if (new_t->state() != Task::Ready || !new_t->initialize())
-    {
-      delete new_t;
-      return 0;
-    }
-
-  return new_t;
+  return 0;
 }
 
-IMPLEMENTATION [tz]:
-
-#include "vm.h"
+//----------------------------------------------------------------------------
+IMPLEMENTATION [!svm && !vmx && !arm_em_tz]:
 
 PRIVATE inline NOEXPORT
 Kobject_iface *
-Factory::new_vm(Utcb const *)
+Factory::new_vm(Utcb const *, int *err)
 {
-  return Vm::create(this);
+  *err = L4_err::ENodev;
+  return 0;
 }
 
-//----------------------------------------------------------------------------
-IMPLEMENTATION [!svm && !tz && !vmx]:
-
-PRIVATE inline NOEXPORT
-Kobject_iface *
-Factory::new_vm(Utcb const *)
-{ return (Kobject_iface*)(-L4_err::EInval); }
-
 // ------------------------------------------------------------------------
 INTERFACE [debug]:
 
@@ -329,15 +303,15 @@ INTERFACE [debug]:
 EXTENSION class Factory
 {
 private:
-  struct Log_entry
+  struct Log_entry : public Tb_entry
   {
     Smword op;
-    Mword buffer;
+    Cap_index buffer;
     Mword id;
     Mword ram;
     Mword newo;
+    unsigned print(int max, char *buf) const;
   };
-  static unsigned log_fmt(Tb_entry *, int, char *) asm ("__factory_log_fmt");
 };
 
 // ------------------------------------------------------------------------
@@ -345,17 +319,17 @@ IMPLEMENTATION [debug]:
 
 IMPLEMENT
 unsigned
-Factory::log_fmt(Tb_entry *e, int maxlen, char *buf)
+Factory::Log_entry::print(int maxlen, char *buf) const
 {
   static char const *const ops[] =
   { /*   0 */ "gate", "irq", 0, 0, 0, 0, 0, 0,
     /*  -8 */ 0, 0, 0, "task", "thread", 0, 0, "factory",
     /* -16 */ "vm", 0, 0, 0, "sem" }; 
-  Log_entry *le = e->payload<Log_entry>();
-  char const *op = -le->op <= (int)(sizeof(ops)/sizeof(ops[0]))
-    ? ops[-le->op] : "invalid op";
-  if (!op)
-    op = "(nan)";
+  char const *_op = -op <= (int)(sizeof(ops)/sizeof(ops[0]))
+    ? ops[-op] : "invalid op";
+  if (!_op)
+    _op = "(nan)";
 
-  return snprintf(buf, maxlen, "factory=%lx [%s] new=%lx cap=[C:%lx] ram=%lx", le->id, op, le->newo, le->buffer, le->ram);
+  return snprintf(buf, maxlen, "factory=%lx [%s] new=%lx cap=[C:%lx] ram=%lx",
+                  id, _op, newo, cxx::int_value<Cap_index>(buffer), ram);
 }