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