1 /*
2 * (c) 2010 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 "lua.h"
10 #include "lua_cap.h"
11 #include "debug.h"
12
13
14 #include <l4/re/util/cap_alloc>
15 #include <l4/sys/types.h>
16 #include <l4/sys/meta>
17
18 namespace Lua {
19
20 void
get_cap_cast_table(lua_State * l)21 get_cap_cast_table(lua_State *l)
22 {
23 lua_getglobal(l, package);
24 lua_getfield(l, LUA_REGISTRYINDEX, "L4::Ned::TYPES");
25 lua_remove(l, -2);
26 }
27
~Cap()28 Cap::~Cap()
29 {
30 }
31
32 void
create_class(lua_State * l,Register_methods * rm,char const * type)33 Cap::create_class(lua_State *l, Register_methods *rm, char const *type)
34 {
35 lua_newtable(l);
36 rm(l);
37 lua_pushstring(l, type);
38 lua_setfield(l, -2, "_CLASS_NAME");
39 }
40
41 void
get_class(lua_State * l)42 Cap::get_class(lua_State *l)
43 {
44 get_cap_cast_table(l);
45 lua_getfield(l, -1, "void");
46 lua_remove(l, -2);
47 }
48
49 static int
is_valid(lua_State * l)50 is_valid(lua_State *l)
51 {
52 Cap *n = check_cap(l, 1);
53 lua_pushboolean(l, n && n->cap<void>().is_valid());
54 return 1;
55 }
56
57 static int
gc_cap(lua_State * l)58 gc_cap(lua_State *l)
59 {
60 Lua::Cap *n = check_cap(l, 1);
61 n->~Cap();
62 return 1;
63 }
64
65
66 static int
tostring(lua_State * l)67 tostring(lua_State *l)
68 {
69 Lua::Cap *n = check_cap(l, 1);
70 lua_getuservalue(l, 1);
71 lua_rawgeti(l, -1, 0);
72 char const *type = "void";
73 if (!lua_isnil(l, -1))
74 {
75 lua_getfield(l, -1, "_CLASS_NAME");
76 type = lua_tostring(l, -1);
77 }
78
79 if (n->cap<void>().is_valid())
80 lua_pushfstring(l, "L4::Cap<%s>[%p] r=%p f=%p", type,
81 (void*)(n->cap<void>().cap()),
82 (void*)(l4_addr_t)n->all_rights(), (void*)(l4_addr_t)n->flags());
83 else
84 lua_pushfstring(l, "L4::Cap<%s>::Invalid", type);
85 return 1;
86 }
87
88 static Cap *
__set_rights(lua_State * l,unsigned r)89 __set_rights(lua_State *l, unsigned r)
90 {
91 Lua::Cap *n = check_cap(l, 1);
92 if (n->all_rights() == r)
93 lua_pushvalue(l, 1);
94 else
95 {
96 Lua::Cap *t = n->clone(l);
97 t->set_rights(r);
98 lua_getuservalue(l, 1);
99 lua_setuservalue(l, -2);
100 return t;
101 }
102
103 return n;
104 }
105
106 static int
__set_mode_call(lua_State * l)107 __set_mode_call(lua_State *l)
108 {
109 Cap *c;
110 if (lua_gettop(l) >= 2 && !lua_isnil(l, 2))
111 {
112 unsigned rights = L4_CAP_FPAGE_R;
113 if (lua_isnumber(l, 2))
114 rights = lua_tointeger(l, 2);
115 else
116 {
117 for (char const *r = lua_tostring(l, 2); *r; ++r)
118 {
119 switch (*r)
120 {
121 case 'r':
122 case 'R': rights |= L4_CAP_FPAGE_R; break;
123 case 'w':
124 case 'W': rights |= L4_CAP_FPAGE_W; break;
125 case 's':
126 case 'S': rights |= L4_CAP_FPAGE_S; break;
127 case 'd':
128 case 'D': rights |= L4_CAP_FPAGE_D; break;
129 case 'n':
130 case 'N': rights |= L4_FPAGE_C_NO_REF_CNT; break;
131 case 'c':
132 case 'C': rights |= L4_FPAGE_C_OBJ_RIGHT1; break;
133 }
134 }
135 }
136 __set_rights(l, rights);
137 return 1;
138 }
139 else
140 c = check_cap(l, 1);
141
142 lua_pushinteger(l, c->rights());
143
144 return 1;
145 }
146
147
148 static int
__full(lua_State * l)149 __full(lua_State *l)
150 {
151 __set_rights(l, 0xef);
152 return 1;
153 }
154
155
156 bool
find_dynamic_type(lua_State * l) const157 Cap::find_dynamic_type(lua_State *l) const
158 {
159 using L4Re::Util::Ref_cap;
160 Dbg dbg(Dbg::Warn, "lua");
161 Ref_cap<L4::Meta>::Cap _meta = L4::cap_cast<L4::Meta>(_c);
162 long proto = 0;
163 char name_buf[256];
164 L4::Ipc::String<char> name(sizeof(name_buf), name_buf);
165 int err = l4_error(_meta->interface(0, &proto, &name));
166 if (err < 0)
167 {
168 dbg.printf("Warning: Capability %lx does not support the meta protocol: %d\n",
169 _c.cap(), err);
170 return false;
171 }
172
173 get_method_table(l, name.data);
174 if (lua_isnil(l, -1))
175 { // no lua representation of type found
176 lua_pop(l, -1);
177 return false;
178 }
179
180 return true;
181 }
182
183 int
index(lua_State * l) const184 Cap::index(lua_State *l) const
185 {
186 get_method_table(l, "void"); // push table
187 lua_pushvalue(l, 2); // push key
188 lua_gettable(l, -2);
189
190 if (!lua_isnil(l, -1))
191 return 1;
192
193 lua_pop(l, 2); // pop nil result, and method table
194
195 lua_getuservalue(l, 1);
196 lua_rawgeti(l, -1, 0);
197 if (lua_isnil(l, -1))
198 {
199 lua_pop(l, 1);
200 if (!find_dynamic_type(l))
201 return 0;
202
203 lua_pushvalue(l, -1); // keep table after set
204 lua_rawseti(l, -3, 0);
205 }
206
207 lua_pushvalue(l, 2); // push key
208 lua_gettable(l, -2);
209 return 1;
210 }
211
__index(lua_State * l)212 static int __index(lua_State *l)
213 {
214 Lua::Cap *n = Lua::check_cap(l, 1);
215 return n->index(l);
216 }
217
218 static
init_cap_metatable(lua_State * l)219 void init_cap_metatable(lua_State *l)
220 {
221 Lua::register_method(l, "__gc", gc_cap);
222 Lua::register_method(l, "__tostring", tostring);
223 Lua::register_method(l, "__index", __index);
224 }
225
226 static
push_cap_metatable(lua_State * l)227 void push_cap_metatable(lua_State *l)
228 {
229 if (luaL_newmetatable(l, CAP_TYPE))
230 init_cap_metatable(l);
231 }
232
set_cap_metatable(lua_State * l)233 void set_cap_metatable(lua_State *l)
234 {
235 push_cap_metatable(l);
236 lua_setmetatable(l, -2);
237 }
238
239 int
get_method_table(lua_State * l,char const * typ) const240 Cap::get_method_table(lua_State *l, char const *typ) const
241 {
242 get_cap_cast_table(l);
243 lua_getfield(l, -1, typ /*type()*/);
244 lua_remove(l, -2);
245 return 1;
246 }
247
248 #if 0
249 if (luaL_newmetatable(l, type()))
250 {
251 luaL_register(l, NULL, l4_cap_class);
252 return 1;
253 }
254 return 0;
255 }
256 #endif
257
258 Cap *
push_void_cap(lua_State * l)259 push_void_cap(lua_State *l)
260 {
261 Cap *c = new (lua_newuserdata(l, sizeof(Cap))) Cap();
262 set_cap_metatable(l);
263 lua_newtable(l);
264 lua_setuservalue(l, -2);
265 return c;
266 }
267
268
269 Cap *
push_new_cap(lua_State * l,bool void_cap)270 push_new_cap(lua_State *l, bool void_cap)
271 {
272 int const frame = lua_gettop(l);
273 get_cap_cast_table(l);
274 lua_pushvalue(l, frame);
275 //long proto = lua_tointeger(l, frame);
276 lua_remove(l, frame);
277 lua_gettable(l, frame);
278 lua_remove(l, frame); // discard cast table
279
280 // and the type table or nil at index 'frame'
281
282 Cap *nc = 0;
283 bool found_type;
284 if ((found_type = !lua_isnil(l, frame)) || void_cap)
285 nc = push_void_cap(l); // cap at frame + 1
286
287 if (found_type)
288 {
289 lua_getuservalue(l, frame + 1);
290 lua_pushvalue(l, frame);
291 lua_rawseti(l, -2, 0);
292 lua_pop(l, 1); // pop env table
293 }
294
295 lua_remove(l, frame); // cap or nothing at frame
296 return nc;
297 }
298
299 void
register_cap(lua_State * l,char const * name,L4::Cap<void> i,long proto)300 register_cap(lua_State *l, char const *name, L4::Cap<void> i, long proto)
301 {
302 lua_pushinteger(l, proto);
303 Cap *c = push_new_cap(l, true);
304 c->set(Cap::C<void>::Cap(i));
305 c->set_rights(L4_CAP_FPAGE_RWS);
306 lua_setfield(l, -2, name);
307 }
308
309 static int
__cast(lua_State * l)310 __cast(lua_State *l)
311 {
312 if (lua_gettop(l) > 2)
313 luaL_error(l, "too many arguments to L4.cast (expected 2: type and cap)");
314
315 if (lua_isfunction(l, 2))
316 lua_call(l, 0, 1);
317
318 Cap *c = check_cap(l, 2);
319 lua_pushvalue(l, 1);
320 Cap *nc = push_new_cap(l, false);
321 if (nc)
322 {
323 nc->assign(c);
324 return 1;
325 }
326
327 lua_pushnil(l);
328 return 1;
329 }
330
331
332 void
init_lua_cap(lua_State * l)333 init_lua_cap(lua_State *l)
334 {
335 static luaL_Reg _cast_f[] =
336 {
337 { "__cast", __cast },
338 { NULL, NULL }
339 };
340
341 Lua::lua_require_module(l, package);
342 luaL_setfuncs(l, _cast_f, 0);
343 lua_newtable(l);
344 lua_pushvalue(l, -1);
345 lua_setfield(l, -3, CAST_TABLE);
346 lua_setfield(l, LUA_REGISTRYINDEX, "L4::Ned::TYPES");
347
348 get_cap_cast_table(l);
349 Cap::create_class(l, Cap::register_methods, "void");
350 lua_setfield(l, -2, "void");
351 lua_pop(l, 2);
352 }
353
354 void
register_methods(lua_State * l)355 Cap::register_methods(lua_State *l)
356 {
357 static const luaL_Reg l4_cap_class[] =
358 {
359 { "is_valid", is_valid },
360 { "svr", __full },
361 { "rights", __set_mode_call },
362 { "mode", __set_mode_call },
363 { "m", __set_mode_call },
364 { NULL, NULL },
365 };
366 luaL_setfuncs(l, l4_cap_class, 0);
367 }
368
369 }
370