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