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