1 /*
2  * (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
3  *     economic rights: Technische Universität Dresden (Germany)
4  *
5  * This file is part of TUD:OS and distributed under the terms of the
6  * GNU General Public License 2.
7  * Please see the COPYING-GPL-2 file for details.
8  */
9 #include <l4/cxx/iostream>
10 #include "name_space.h"
11 #include "debug.h"
12 #include "globals.h"
13 #include "string.h"
14 #include "server_obj.h"
15 
16 #include <l4/cxx/l4iostream>
17 #include <l4/cxx/minmax>
18 #include <l4/cxx/unique_ptr>
19 #include <l4/sys/assert.h>
20 
21 #include <cstring>
22 #include <cstdlib>
23 #include <cassert>
24 
root_name_space()25 Moe::Name_space *root_name_space()
26 {
27   static auto *_root = Moe::Moe_alloc::allocator()->make_obj<Moe::Name_space>();
28   return _root;
29 }
30 
31 namespace Moe {
32 
33 static Dbg dbg(Dbg::Name_space, "ns");
34 
~Entry()35 Entry::~Entry()
36 {
37   qalloc()->free(const_cast<char *>(_name.start()));
38 
39   if (_flags & F_allocated)
40     object_pool.cap_alloc()->free(cap());
41 
42   // explicit destructor call required because of union
43   if (is_local())
44     _obj.~Weak_ref();
45 }
46 
47 
48 void
set(L4::Cap<void> cap)49 Entry::set(L4::Cap<void> cap)
50 {
51   _cap = cap.cap();
52   _flags = (_flags | F_cap) & ~F_local;
53 }
54 
55 void
set(Moe::Server_object * o)56 Entry::set(Moe::Server_object *o)
57 {
58   new (&_obj) Weak_ref(o);
59 
60   _flags |= F_local | F_cap;
61 }
62 
63 void
set_epiface(l4_umword_t data)64 Entry::set_epiface(l4_umword_t data)
65 {
66   assert(!is_valid());
67 
68   auto *ef = static_cast<Moe::Server_object*>(object_pool.find(data));
69 
70   if (!ef)
71     throw L4::Runtime_error(-L4_EINVAL);
72 
73   set(ef);
74 
75   // make sure rights are restricted to the mapped rights
76   _flags &= (data & 0x3UL) | ~0x3UL;
77 }
78 
79 void
set_cap_copy(L4::Cap<L4::Kobject> cap)80 Entry::set_cap_copy(L4::Cap<L4::Kobject> cap)
81 {
82   assert(!is_valid());
83 
84   auto nc = object_pool.cap_alloc()->alloc();
85   nc.move(cap);
86 
87   set(nc);
88   _flags |= F_allocated | F_cap;
89 }
90 
91 
~Name_space()92 Name_space::~Name_space()
93 {
94   _tree.remove_all([](Entry *e) { delete e; });
95 }
96 
97 Entry *
check_existing(Name_buffer const & name,unsigned flags)98 Name_space::check_existing(Name_buffer const &name, unsigned flags)
99 {
100   Entry *n = find(Entry::Name(name.data, name.length));
101   if (n)
102     {
103       if (!n->is_valid())
104         return n;
105 
106       if (!n->is_dynamic())
107         throw L4::Element_already_exists();
108 
109       if (!(flags & L4Re::Namespace::Overwrite)
110           && n->cap().validate(L4_BASE_TASK_CAP).label() > 0)
111         throw L4::Element_already_exists();
112 
113       return n;
114     }
115 
116   return 0;
117 }
118 
119 Entry *
find_iter(Entry::Name const & pname) const120 Name_space::find_iter(Entry::Name const &pname) const
121 {
122   Entry::Name name = pname;
123   dbg.printf("resolve '%.*s': ", name.len(), name.start());
124   Name_space const *ns = this;
125   while (ns)
126     {
127       cxx::String::Index sep = name.find("/");
128       cxx::String part;
129       if (!name.eof(sep))
130         part = name.head(sep);
131       else
132         part = name;
133 
134       dbg.cprintf(" '%.*s'", part.len(), part.start());
135       Entry *o = ns->find(Entry::Name(part.start(), part.len()));
136 
137       if (!o || !o->is_local())
138         {
139           dbg.cprintf(": resolution failed: '%.*s' remaining\n",
140                       name.len(), name.start());
141           return 0;
142         }
143 
144       ns = dynamic_cast<Name_space const *>(o->_obj.get());
145       if (ns)
146         {
147           if (!name.eof(sep))
148             {
149               name = name.substr(sep + 1);
150               continue;
151             }
152         }
153 
154       dbg.cprintf(": found object: %p (%s)\n", o->_obj.get(),
155                   o->_obj ? typeid(*(o->_obj.get())).name() : "");
156 
157       return o;
158     }
159 
160   return 0;
161 }
162 
163 
164 int
op_register_obj(L4Re::Namespace::Rights,unsigned flags,Name_buffer const & name,L4::Ipc::Snd_fpage & cap)165 Name_space::op_register_obj(L4Re::Namespace::Rights, unsigned flags,
166                             Name_buffer const &name, L4::Ipc::Snd_fpage &cap)
167 {
168   if (name.length == 0 || memchr(name.data, '/', name.length))
169     return -L4_EINVAL;
170 
171   if (cap.local_id_received())
172     return -L4_EINVAL;
173 
174 
175   // check if we are are going to overwrite
176   Entry *existing = check_existing(name, flags);
177   // make ourselves a new entry
178   cxx::unique_ptr<Entry> n(create_entry(name, flags));
179 
180   if (cap.id_received())
181     n->set_epiface(cap.data());
182   else if (cap.cap_received())
183     n->set_cap_copy(L4::Cap<L4::Kobject>(Rcv_cap << L4_CAP_SHIFT));
184   else if (cap.is_valid())
185     // received a valid cap we cannot handle
186     return -L4_EINVAL;
187 
188   // insert, overwriting if necessary
189   if (existing)
190     {
191       // clean up the overwritten entry
192       cxx::unique_ptr<Entry> to_delete(existing);
193       remove(existing->name());
194     }
195 
196   bool r = insert(n.get());
197   l4_check(r);
198   n.release();
199 
200   return L4_EOK;
201 }
202 
203 int
op_unlink(L4Re::Namespace::Rights,Name_buffer const & name)204 Name_space::op_unlink(L4Re::Namespace::Rights, Name_buffer const &name)
205 {
206   auto *sep = (char const *)memchr(name.data, '/', name.length);
207   unsigned long part;
208   if (sep)
209     part = sep - name.data;
210   else
211     part = name.length;
212 
213   Entry *n = find(Entry::Name(name.data, part));
214   if (!n)
215     return -L4_ENOENT;
216 
217   if (!n->is_dynamic())
218     return -L4_EACCESS;
219 
220   remove(n->name());
221 
222   // get rid of the entry
223   cxx::unique_ptr<Entry> to_delete(n);
224 
225   return L4_EOK;
226 }
227 
228 int
op_query(L4Re::Namespace::Rights,Name_buffer const & name,L4::Ipc::Snd_fpage & snd_cap,L4::Ipc::Opt<L4::Opcode> & dummy,L4::Ipc::Opt<L4::Ipc::Array_ref<char,unsigned long>> & out_name)229 Name_space::op_query(L4Re::Namespace::Rights,
230                      Name_buffer const &name,
231                      L4::Ipc::Snd_fpage &snd_cap,
232                      L4::Ipc::Opt<L4::Opcode> &dummy,
233                      L4::Ipc::Opt<L4::Ipc::Array_ref<char, unsigned long> > &out_name)
234 {
235 #if 0
236   dbg.printf("query: [%ld] '%.*s'\n", name.length, (int)name.length, name.data);
237 #endif
238 
239   auto *sep = (char const *)memchr(name.data, '/', name.length);
240   unsigned long part;
241   if (sep)
242     part = sep - name.data;
243   else
244     part = name.length;
245 
246   Entry *n = find(Entry::Name(name.data, part));
247   if (!n)
248     return -L4_ENOENT;
249   if (!n->is_valid())
250     return -L4_EAGAIN;
251 
252   if (n->cap().validate(L4_BASE_TASK_CAP).label() <= 0)
253     {
254       if (n->is_dynamic())
255         {
256           cxx::unique_ptr<Entry> old(n);
257           remove(n->name());
258         }
259       return -L4_ENOENT;
260     }
261 
262   // make picky clients happy
263   dummy.set_valid();
264 
265   l4_umword_t result = 0;
266 
267   out_name.set_valid();
268   if (part < name.length)
269     {
270       result |= L4Re::Namespace::Partly_resolved;
271       memcpy(out_name->data, name.data + part + 1, name.length - part - 1);
272       out_name->length = name.length - part - 1;
273     }
274   else
275     out_name->length = 0;
276 
277   unsigned flags = L4_CAP_FPAGE_R;
278   if (n->is_rw())     flags |= L4_CAP_FPAGE_W;
279   if (n->is_strong()) flags |= L4_CAP_FPAGE_S;
280 
281   snd_cap = L4::Ipc::Snd_fpage(n->cap(), flags);
282   dbg.printf(" result = %lx flgs=%x strg=%d\n",
283               result, flags, (int)n->is_strong());
284   return result;
285 }
286 
287 
288 void
dump(bool rec,int indent) const289 Name_space::dump(bool rec, int indent) const
290 {
291   Name_space const *n;
292   //L4::cout << "MOE: Name space dump (" << obj_cap() << ")\n";
293   for (Const_iterator i = begin(); i != end(); ++i)
294     {
295       for (int x = 0; x < indent; ++x)
296         L4::cout << "  ";
297 
298       L4::cout << "  " << i->name()  << " -> " << i->cap();
299       if (i->is_local())
300         L4::cout << " o=" << (void *)i->obj();
301       L4::cout << " f=" << i->_flags << '\n';
302       if (rec && i->is_local()
303           && (n = dynamic_cast<Name_space const *>(i->obj())))
304         {
305           n->dump(rec, indent + 1);
306         }
307     }
308 }
309 
310 }
311