1 /*
2  * (c) 2010 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 #include "app_task.h"
11 #include "app_model.h"
12 #include "debug.h"
13 
14 #include <l4/cxx/ref_ptr>
15 #include <l4/libloader/elf>
16 #include <l4/util/bitops.h>
17 
18 #include <lua.h>
19 #include <lauxlib.h>
20 #include <lualib.h>
21 
22 #include <pthread-l4.h>
23 #include "lua.h"
24 #include "lua_cap.h"
25 #include "server.h"
26 
27 using L4Re::chksys;
28 
operator new(size_t,void * p)29 inline void *operator new (size_t, void *p) throw() { return p; }
30 namespace Lua { namespace {
31 
32 struct Obs_iface : L4::Kobject_0t<Obs_iface>
33 {
34   struct Task
35   {
36     App_task *p;
37     Task() = default;
TaskLua::__anon060973880111::Obs_iface::Task38     Task(App_task *p) : p(p) {}
39   };
40 
41   L4_INLINE_RPC(long, wait, (l4_cap_idx_t thread, Task task));
42 
43   typedef L4::Typeid::Rpcs<wait_t> Rpcs;
44 };
45 
46 class Observer :
47   public L4::Epiface_t<Observer, Obs_iface, Ned::Server_object>
48 {
49 public:
50   long op_wait(Obs_iface::Rights, l4_cap_idx_t thread, Obs_iface::Task task);
51 };
52 
53 static Observer *observer;
54 
55 long
op_wait(Obs_iface::Rights,l4_cap_idx_t thread,Obs_iface::Task task)56 Observer::op_wait(Obs_iface::Rights, l4_cap_idx_t thread, Obs_iface::Task task)
57 {
58   App_task *t = task.p;
59 
60   if (t->state() == App_task::Zombie)
61     return 0;
62 
63   t->observer(thread);
64   return -L4_ENOREPLY;
65 }
66 
67 class Am : public Rmt_app_model
68 {
69 private:
70   // simple container for NUM Ref_caps
71   template<unsigned NUM>
72   class Cap_stack
73   {
74   private:
75     unsigned _i = 0;
76     L4Re::Util::Ref_cap<void>::Cap _c[NUM];
77 
78   public:
push(L4Re::Util::Ref_cap<void>::Cap c)79     void push(L4Re::Util::Ref_cap<void>::Cap c)
80     {
81       if (_i >= NUM)
82         throw "internal error: too many temporary caps for stack";
83 
84       _c[_i++] = c;
85     }
86   };
87 
88   lua_State *_lua;
89   int _argc;
90   int _env_idx;
91   int _cfg_idx;
92   int _arg_idx;
93 
94   L4Re::Util::Ref_cap<L4::Factory>::Cap _rm_fab;
95 
96   /**
97    * container to store some ref counted caps to make sure the Lua GC
98    * does not collect them before we map/use them for application.
99    */
100   Cap_stack<6> _cap_stack;
101 
_cfg_integer(char const * f,l4_umword_t def=0)102   l4_umword_t _cfg_integer(char const *f, l4_umword_t def = 0)
103   {
104     l4_umword_t r = def;
105     lua_getfield(_lua, _cfg_idx, f);
106     if (lua_isnumber(_lua, -1))
107       r = lua_tointeger(_lua, -1);
108 
109     lua_pop(_lua, 1);
110     return r;
111   }
112 
113   template<typename CT>
114   typename L4Re::Util::Ref_cap<CT>::Cap
_cfg_cap(char const * f,l4_fpage_t * r=0)115   _cfg_cap(char const *f, l4_fpage_t *r = 0)
116   {
117     typedef typename L4Re::Util::Ref_cap<CT>::Cap R_cap;
118 
119     lua_getfield(_lua, _cfg_idx, f);
120     while (lua_isfunction(_lua, -1))
121       {
122         lua_pushvalue(_lua, _cfg_idx);
123         lua_call(_lua, 1, 1);
124       }
125 
126     if (lua_isnil(_lua, -1))
127       {
128         //if (r)
129         //  *r = l4_fpage_invalid();
130 
131         lua_pop(_lua, 1);
132         return R_cap();
133       }
134 
135     Cap *c = (Cap *)luaL_testudata(_lua, -1, Lua::CAP_TYPE);
136     if (!c)
137       {
138         lua_pop(_lua, 1);
139         luaL_error(_lua, "error: capability expected '%s'\n", f);
140         return R_cap();
141       }
142 
143     if (r)
144       //*r = c->fpage();
145       *r = c ? c->fpage() : l4_fpage_invalid();
146 
147     R_cap res = c->cap<CT>();
148     lua_pop(_lua, 1);
149     return res;
150   }
151 
152 public:
153 
Am(lua_State * l)154   explicit Am(lua_State *l)
155   : Rmt_app_model(), _lua(l), _argc(lua_gettop(l)), _env_idx(0), _cfg_idx(1),
156     _arg_idx(2)
157   {
158     if (_argc > 2 && lua_type(_lua, _argc) == LUA_TTABLE)
159       _env_idx = _argc;
160 
161     if (_env_idx)
162       --_argc;
163   }
164 
push_initial_caps(l4_cap_idx_t start)165   l4_cap_idx_t push_initial_caps(l4_cap_idx_t start)
166   {
167     lua_getfield(_lua, _cfg_idx, "caps");
168     int tab = lua_gettop(_lua);
169 
170     if (lua_isnil(_lua, tab))
171       {
172 	lua_pop(_lua, 1);
173         return start;
174       }
175 
176     lua_pushnil(_lua);
177     while (lua_next(_lua, tab))
178       {
179 	char const *r = luaL_checkstring(_lua, -2);
180         if (!l4re_env_cap_entry_t::is_valid_name(r))
181           luaL_error(_lua, "Capability name '%s' too long", r);
182 	while (lua_isfunction(_lua, -1))
183 	  {
184 	    lua_pushvalue(_lua, tab);
185 	    lua_call(_lua, 1, 1);
186 	  }
187 
188 	if (!lua_isnil(_lua, -1) && lua_touserdata(_lua, -1))
189 	  {
190 	    Lua::check_cap(_lua, -1);
191 	    _stack.push(l4re_env_cap_entry_t(r, get_initial_cap(r, &start)));
192 	  }
193 	lua_pop(_lua, 1);
194       }
195     lua_pop(_lua, 1);
196     return start;
197   }
198 
map_initial_caps(L4::Cap<L4::Task> task,l4_cap_idx_t start)199   void map_initial_caps(L4::Cap<L4::Task> task, l4_cap_idx_t start)
200   {
201     lua_getfield(_lua, _cfg_idx, "caps");
202     int tab = lua_gettop(_lua);
203 
204     if (lua_isnil(_lua, tab))
205       {
206 	lua_pop(_lua, 1);
207         return;
208       }
209 
210     lua_pushnil(_lua);
211     while (lua_next(_lua, tab))
212       {
213 	char const *r = luaL_checkstring(_lua, -2);
214 	while (lua_isfunction(_lua, -1))
215 	  {
216 	    lua_pushvalue(_lua, tab);
217 	    lua_call(_lua, 1, 1);
218 	  }
219 
220 	if (!lua_isnil(_lua, -1) && lua_touserdata(_lua, -1))
221 	  {
222 	    Cap *c = Lua::check_cap(_lua, -1);
223 	    auto idx = get_initial_cap(r, &start);
224 	    chksys(task->map(L4Re::This_task,
225 	                     c->cap<void>().fpage(c->rights()),
226 	                     L4::Cap<void>(idx).snd_base() | c->ext_rights()));
227 	  }
228 	lua_pop(_lua, 1);
229       }
230     lua_pop(_lua, 1);
231   }
232 
launch_loader()233   void launch_loader()
234   {
235     char const *kernel = "rom/l4re";
236     lua_getfield(_lua, _cfg_idx, "l4re_loader");
237     if (lua_isstring(_lua, -1))
238       kernel = lua_tostring(_lua, -1);
239 
240     typedef Ldr::Elf_loader<Am, Dbg> Loader;
241 
242     Dbg ldr(Dbg::Loader, "ldr");
243     Loader _l;
244 
245     _l.launch(this, kernel, ldr);
246 
247     lua_pop(_lua, 1);
248   }
249 
parse_cfg()250   void parse_cfg()
251   {
252     L4Re::Util::Ref_cap<L4::Factory>::Cap user_factory
253       = L4Re::Env::env()->user_factory();
254 
255     prog_info()->mem_alloc = user_factory.fpage();
256     prog_info()->log = L4Re::Env::env()->log().fpage();
257     prog_info()->factory = L4Re::Env::env()->factory().fpage();
258     prog_info()->scheduler = L4Re::Env::env()->scheduler().fpage();
259     //  parser.scheduler_cap.set_fpage(&am.prog_info()->scheduler);
260 
261     prog_info()->ldr_flags = 0;
262     prog_info()->l4re_dbg = 0;
263 
264     if (!_cfg_idx)
265       return;
266 
267     prog_info()->ldr_flags = _cfg_integer("ldr_flags", prog_info()->ldr_flags);
268     prog_info()->l4re_dbg = _cfg_integer("l4re_dbg", prog_info()->l4re_dbg);
269 
270     _cap_stack.push(_cfg_cap<void>("log", &prog_info()->log));
271     _cap_stack.push(_cfg_cap<void>("mem", &prog_info()->mem_alloc));
272     _cap_stack.push(_cfg_cap<void>("factory", &prog_info()->factory));
273     _cap_stack.push(_cfg_cap<void>("scheduler", &prog_info()->scheduler));
274 
275     auto c = _cfg_cap<L4::Factory>("rm_fab");
276     if (c)
277       _rm_fab = c;
278     else
279       _rm_fab = user_factory;
280   }
281 
rm_fab() const282   L4Re::Util::Ref_cap<L4::Factory>::Cap rm_fab() const { return _rm_fab; }
283 
set_task(App_task * t)284   void set_task(App_task *t) { _task = t; }
285 
push_argv_strings()286   void push_argv_strings()
287   {
288     argv.a0 = 0;
289     for (int i = _arg_idx; i <= _argc; ++i)
290       {
291         if (lua_isnil(_lua, i))
292           continue;
293 
294 	size_t l;
295 	char const *r = luaL_checklstring(_lua, i, &l);
296 	argv.al = _stack.push_str(r, l);
297 	if (argv.a0 == 0)
298 	  argv.a0 = argv.al;
299       }
300   }
301 
push_env_strings()302   void push_env_strings()
303   {
304     if (!_env_idx)
305       return;
306 
307     lua_pushnil(_lua);
308     bool _f = true;
309     while (lua_next(_lua, _env_idx))
310       {
311 	size_t kl;
312 	char const *k = luaL_checklstring(_lua, -2, &kl);
313 	size_t vl;
314 	char const *v = luaL_checklstring(_lua, -1, &vl);
315 
316 	_stack.push_str(v, vl);
317 	_stack.push('=');
318 	envp.al = _stack.push_object(k, kl);
319 	if (_f)
320 	  {
321 	    envp.a0 = envp.al;
322 	    _f = false;
323 	  }
324 	lua_pop(_lua, 1);
325       }
326   }
327 };
328 
329 
330 static char const *const APP_TASK_TYPE = "L4_NED_APP_TASK";
331 typedef cxx::Ref_ptr<App_task> App_ptr;
332 
333 static
check_at(lua_State * l,int i)334 App_ptr &check_at(lua_State *l, int i)
335 {
336   App_ptr *t = (App_ptr*)luaL_checkudata(l, i, APP_TASK_TYPE);
337   return *t;
338 }
339 
__task_state(lua_State * l)340 static int __task_state(lua_State *l)
341 {
342   App_ptr t = check_at(l, 1);
343 
344   if (!t)
345     {
346       lua_pushnil(l);
347       return 1;
348     }
349 
350   switch (t->state())
351     {
352     case App_task::Initializing:
353       lua_pushstring(l, "initializing");
354       break;
355 
356     case App_task::Running:
357       lua_pushstring(l, "running");
358       break;
359 
360     case App_task::Zombie:
361       lua_pushstring(l, "zombie");
362       break;
363 
364     default:
365       lua_pushstring(l, "nan");
366       break;
367     }
368 
369   return 1;
370 }
371 
__task_exit_code(lua_State * l)372 static int __task_exit_code(lua_State *l)
373 {
374   App_ptr t = check_at(l, 1);
375   if (!t)
376     lua_pushnil(l);
377   else
378     lua_pushinteger(l, t->exit_code());
379 
380   return 1;
381 }
382 
__task_wait(lua_State * l)383 static int __task_wait(lua_State *l)
384 {
385   App_ptr &t = check_at(l, 1);
386 
387   if (!t)
388     {
389       lua_pushnil(l);
390       return 1;
391     }
392 
393   L4::cap_cast<Obs_iface>(observer->obj_cap())->wait(pthread_l4_cap(pthread_self()), t.get());
394   lua_pushinteger(l, t->exit_code());
395 
396   t = 0; // zap task
397   return 1;
398 }
399 
__task_kill(lua_State * l)400 static int __task_kill(lua_State *l)
401 {
402   App_ptr &t = check_at(l, 1);
403 
404   if (!t)
405     {
406       lua_pushnil(l);
407       return 1;
408     }
409 
410   if (t->state() == App_task::Zombie)
411     {
412       lua_pushinteger(l, t->exit_code());
413       t = 0; // zap task
414       return 1;
415     }
416 
417   t->terminate();
418   t = 0; // kill task
419   lua_pushstring(l, "killed");
420 
421   return 1;
422 }
423 
__task_gc(lua_State * l)424 static int __task_gc(lua_State *l)
425 {
426   App_ptr &t = check_at(l, 1);
427   t = 0; // drop reference to task
428   return 0;
429 }
430 
__task_eq(lua_State * l)431 static int __task_eq(lua_State *l)
432 {
433   App_ptr const &t1 = check_at(l, 1);
434   App_ptr const &t2 = check_at(l, 2);
435   lua_pushboolean(l, t1 == t2);
436   return 1;
437 }
438 
__task_lt(lua_State * l)439 static int __task_lt(lua_State *l)
440 {
441   App_ptr const &t1 = check_at(l, 1);
442   App_ptr const &t2 = check_at(l, 2);
443   lua_pushboolean(l, t1 < t2);
444   return 1;
445 }
446 
__task_le(lua_State * l)447 static int __task_le(lua_State *l)
448 {
449   App_ptr const &t1 = check_at(l, 1);
450   App_ptr const &t2 = check_at(l, 2);
451   lua_pushboolean(l, t1 <= t2);
452   return 1;
453 }
454 
455 static const luaL_Reg _task_ops[] = {
456     { "state", __task_state },
457     { "exit_code", __task_exit_code },
458     { "wait", __task_wait },
459     { "kill", __task_kill },
460     { NULL, NULL }
461 };
462 
463 
exec(lua_State * l)464 static int exec(lua_State *l)
465 {
466   try {
467 
468   Am am(l);
469   am.parse_cfg();
470 
471   App_ptr app_task(new App_task(Ned::server->registry(), am.rm_fab()));
472 
473   if (!app_task)
474     {
475       Err().printf("could not allocate task control block\n");
476       return 0;
477     }
478 
479 
480   am.set_task(app_task.get());
481 
482   app_task->running();
483 
484   am.launch_loader();
485 
486   App_ptr *at = new (lua_newuserdata(l, sizeof(App_ptr))) App_ptr();
487   *at = app_task;
488 
489   luaL_newmetatable(l, APP_TASK_TYPE);
490   lua_setmetatable(l, -2);
491 
492   return 1;
493   } catch (L4::Runtime_error const &e) {
494     luaL_error(l, "could not create process: %s (%s: %d)", e.str(), e.extra_str(), e.err_no());
495   }
496 
497   return 0;
498 }
499 
500 
501 static const luaL_Reg _task_meta_ops[] = {
502     { "__gc", __task_gc },
503     { "__eq", __task_eq },
504     { "__lt", __task_lt },
505     { "__le", __task_le },
506     { NULL, NULL }
507 };
508 
509 class Lib_exec : public Lib
510 {
511 public:
Lib_exec()512   Lib_exec() : Lib(P_env) {}
init(lua_State * l)513   void init(lua_State *l)
514   {
515     static const luaL_Reg _ops[] =
516     {
517       { "exec", exec },
518       { NULL, NULL }
519     };
520     Lua::lua_require_module(l, "L4");
521     luaL_setfuncs(l, _ops, 0);
522 
523     if (luaL_newmetatable(l, APP_TASK_TYPE))
524       {
525 	lua_newtable(l);
526 	luaL_setfuncs(l, _task_ops, 0);
527 	lua_setfield(l, -2, "__index");
528 	luaL_setfuncs(l, _task_meta_ops, 0);
529       }
530     lua_pop(l, 2);
531 
532     observer = new Observer();
533     L4Re::chkcap(Ned::server->registry()->register_obj(observer),
534                  "Register observer endpoint.");
535   }
536 };
537 
538 static Lib_exec __lib;
539 
540 }}
541 
542