1 /*
2  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *               Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10 #pragma once
11 
12 #include <l4/sys/task.h>
13 #include <l4/sys/factory.h>
14 #include <l4/sys/types.h>
15 #include <l4/sys/thread>
16 
17 #include <l4/re/util/bitmap_cap_alloc>
18 #include <l4/re/error_helper>
19 #include <l4/re/env>
20 
21 #include <l4/cxx/exceptions>
22 #include <l4/cxx/hlist>
23 
24 #include "early.h"
25 #include "server_obj.h"
26 
27 #include <cstring>
28 #include <cassert>
29 #include <cstdio>
30 
31 #define DEBUG_CAP_ALLOC 0
32 
33 enum
34 {
35   Rcv_cap = 0x100,
36 };
37 
38 class Cap_alloc;
39 
40 class Object_pool
41 : public L4::Basic_registry,
42   public L4::Ipc_svr::Server_iface,
43   private L4::Irqep_t<Object_pool>
44 {
45   friend struct L4::Irqep_t<Object_pool>;
46 
47 public:
48   explicit Object_pool(Cap_alloc *ca);
49   Cap_alloc *cap_alloc() const { return _cap_alloc; }
50   cxx::H_list_t<Moe::Server_object> life;
51   int alloc_buffer_demand(L4::Type_info::Demand const &demand) override
52   {
53     if (demand.caps > 1
54         || demand.ports != 0
55         || demand.mem != 0
56         || demand.flags != 0)
57       return -L4_EINVAL;
58 
59     return 0;
60   }
61 
62   L4::Cap<void> get_rcv_cap(int index) const override
63   {
64     if (index == 0)
65       return L4::Cap<void>(Rcv_cap << L4_CAP_SHIFT);
66     else
67       return L4::Cap<void>::Invalid;
68   }
69 
70   int realloc_rcv_cap(int) override
71   { return -L4_ENOMEM; }
72 
73   int add_timeout(L4::Ipc_svr::Timeout *, l4_kernel_clock_t) override
74   { return -L4_ENODEV; }
75 
76   int remove_timeout(L4::Ipc_svr::Timeout *) override
77   { return -L4_ENODEV; }
78 
79 private:
80   Cap_alloc *_cap_alloc;
81 
82   void handle_irq()
83   {
84     l4_utcb_t *utcb = l4_utcb();
85     for (auto i = life.begin(); i != life.end();)
86       {
87         if (i->obj_cap() && !i->obj_cap().validate(utcb).label())
88           delete *i;
89         else
90           ++i;
91       }
92   }
93 };
94 
95 class Cap_alloc
96 {
97 public:
98   enum
99   {
100     Non_gc_caps = 8192,
101     Non_gc_cap_0 = Rcv_cap + 1,
102   };
103 
104 private:
105   // caps mainly used for things from outside (registered in name spaces)
106   // this are usually not a lot
107   L4Re::Util::Cap_alloc<Non_gc_caps> _non_gc;
108 
109 public:
110   Cap_alloc() : _non_gc(Non_gc_cap_0)
111   {}
112 
113   L4::Cap<L4::Kobject> alloc()
114   {
115      L4::Cap<L4::Kobject> cap = _non_gc.alloc<L4::Kobject>();
116 #if DEBUG_CAP_ALLOC
117      L4::cerr << "AC->" << L4::n_hex(cap.cap()) << "\n";
118 #endif
119      return cap;
120   }
121 
122   template< typename T >
123   L4::Cap<T> alloc() { return L4::cap_cast<T>(alloc()); }
124 
125   L4::Cap<L4::Kobject> alloc(Moe::Server_object *_o)
126   {
127     extern Object_pool object_pool;
128     // make sure we register an Epiface ptr
129     L4::Epiface *o = _o;
130     L4::Cap<L4::Kobject> cap = _non_gc.alloc<L4::Kobject>();
131 #if  DEBUG_CAP_ALLOC
132     L4::cerr << "ACO->" << L4::n_hex(cap.cap()) << "\n";
133 #endif
134     if (!cap.is_valid())
135       throw(L4::Out_of_memory());
136 
137     l4_umword_t id = l4_umword_t(o);
138     l4_factory_create_gate(L4_BASE_FACTORY_CAP, cap.cap(),
139                            L4_BASE_THREAD_CAP, id);
140 
141     _o->set_server(&object_pool, cap, true);
142     return cap;
143   }
144 
145   bool free(L4::Cap<void> const &cap, l4_umword_t unmap_flags = L4_FP_ALL_SPACES)
146   {
147     if (!cap.is_valid())
148       return false;
149 
150     if ((cap.cap() >> L4_CAP_SHIFT) >= Non_gc_cap_0)
151       _non_gc.free(cap, L4_BASE_TASK_CAP, unmap_flags);
152     else
153       return false;
154 
155     return true;
156   }
157 
158 };
159 
160 inline Object_pool::Object_pool(Cap_alloc *ca) : _cap_alloc(ca)
161 {
162   // make sure we register an Epiface PTR
163   L4::Epiface *self = this;
164   auto c = early_chkcap(cap_alloc()->alloc<L4::Irq>(),
165                         "Moe::Object_pool: Failed to allocate capability\n");
166   early_chksys(L4Re::Env::env()->factory()->create(c),
167                "Moe::Object_pool: Failed to create IRQ\n");
168   early_chksys(c->bind_thread(L4::Cap<L4::Thread>(L4_BASE_THREAD_CAP),
169                               l4_umword_t(self)),
170                "Moe::Object_pool: Failed to bind IRQ\n");
171   set_server(this, c, true);
172   early_chksys(L4::Cap<L4::Thread>(L4_BASE_THREAD_CAP)->register_del_irq(c),
173                "Moe::Object_pool: Failed to register deletion IRQ\n");
174 }
175