]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/moe/server/src/main.cc
Inital import
[l4.git] / l4 / pkg / moe / server / src / main.cc
1 /*
2  * (c) 2008-2009 Technische Universität Dresden
3  * This file is part of TUD:OS and distributed under the terms of the
4  * GNU General Public License 2.
5  * Please see the COPYING-GPL-2 file for details.
6  */
7
8 #include <l4/crtn/crt0.h>
9 #include <l4/util/util.h>
10 #include <l4/sigma0/sigma0.h>
11
12 #include <l4/sys/kip>
13 #include <l4/sys/utcb.h>
14 #include <l4/sys/debugger.h>
15 #include <l4/sys/scheduler>
16 #include <l4/sys/thread>
17
18 #include <l4/cxx/exceptions>
19 #include <l4/cxx/ipc_stream>
20
21 #include <l4/cxx/iostream>
22 #include <l4/cxx/l4iostream>
23
24 #include <l4/util/mb_info.h>
25
26 #include <cctype>
27 #include <cstdlib>
28 #include <cstring>
29 #include <cstdio>
30
31 #include "boot_fs.h"
32 #include "exception.h"
33 #include "globals.h"
34 #include "loader_elf.h"
35 #include "log.h"
36 #include "name_space.h"
37 #include "page_alloc.h"
38 #include "pages.h"
39 #include "vesa_fb.h"
40 #include "dataspace_static.h"
41 #include "debug.h"
42 #include "args.h"
43
44 #include <l4/re/env>
45 #include <gc.h>
46
47 using L4Re::Util::Names::Obj;
48
49 static L4Re::Env my_env;
50
51 // Implementation
52 extern "C" void _exit(int status);
53
54 void _exit(int status)
55 {
56   L4::cout << "MOE: is terminating with " << status << ", very bad......\n";
57   l4_sleep_forever();
58 }
59
60 unsigned Moe::l4re_dbg = Dbg::Warn;
61 unsigned Moe::ldr_flags;
62
63
64 static Dbg info(Dbg::Info);
65 static Dbg boot(Dbg::Boot);
66 static Dbg warn(Dbg::Warn);
67
68 static
69 l4_kernel_info_t const *map_kip()
70 {
71   _current_kip = l4sigma0_map_kip(Sigma0_cap, 0, L4_WHOLE_ADDRESS_SPACE);
72
73   if (!_current_kip)
74     {
75       Err(Err::Fatal).printf("could not map KIP\n");
76       exit(1);
77     }
78
79
80   boot.printf("KIP @%p\n",kip());
81   return kip();
82 }
83
84 static
85 char *my_cmdline()
86 {
87   l4util_mb_info_t const *_mbi_ = (l4util_mb_info_t const *)kip()->user_ptr;
88   boot.printf("mbi @%p\n", _mbi_);
89   l4util_mb_mod_t const *modules = (l4util_mb_mod_t const *)_mbi_->mods_addr;
90   unsigned num_modules = _mbi_->mods_count;
91   char *cmdline = 0;
92
93   for (unsigned mod = 0; mod < num_modules; ++mod)
94     {
95       if (strstr((char const *)modules[mod].cmdline, PROG))
96         {
97           cmdline = (char *)modules[mod].cmdline;
98           break;
99         }
100     }
101
102   if (!cmdline)
103     cmdline = (char *)_mbi_->cmdline;
104
105   static char default_cmdline[] = "";
106
107   if (!cmdline)
108     {
109       Dbg(Dbg::Warn).printf("no command line found, use default!\n");
110       cmdline = default_cmdline;
111     }
112
113   return cmdline;
114 }
115
116
117
118 static void find_memory()
119 {
120   using Moe::Pages::pages;
121   l4_addr_t addr;
122   l4_addr_t min_addr = ~0UL;
123   l4_addr_t max_addr = 0;
124
125   for (unsigned order = 30 /*1G*/; order >= L4_LOG2_PAGESIZE; --order)
126     {
127       while (!l4sigma0_map_anypage(Sigma0_cap, 0, L4_WHOLE_ADDRESS_SPACE,
128                                    &addr, order))
129         {
130           unsigned long size = 1UL << order;
131
132           if (addr == 0)
133             {
134               addr = L4_PAGESIZE;
135               size -= L4_PAGESIZE;
136               if (!size)
137                 continue;
138             }
139
140           if (addr < min_addr) min_addr = addr;
141           if (addr + size > max_addr) max_addr = addr + size;
142
143           Single_page_alloc_base::_free((void*)addr, size, true);
144         }
145     }
146
147   info.printf("found %ld KByte free memory\n",
148               Single_page_alloc_base::_avail() / 1024);
149
150   // adjust min_addr and max_addr to also contain boot modules
151   L4::Kip::Mem_desc const *md  = L4::Kip::Mem_desc::first(kip());
152   L4::Kip::Mem_desc const *end = md + L4::Kip::Mem_desc::count(kip());
153
154   for (; md < end; ++md)
155     {
156       if (md->is_virtual())
157         continue;
158
159       L4::Kip::Mem_desc::Mem_type type = md->type();
160       unsigned long end = l4_round_page(md->end());
161       unsigned long start = l4_trunc_page(md->start());
162       switch (type)
163         {
164         case L4::Kip::Mem_desc::Bootloader:
165           if (start < min_addr)
166             min_addr = start;
167           if (end > max_addr)
168             max_addr = end;
169           break;
170         case L4::Kip::Mem_desc::Conventional:
171         case L4::Kip::Mem_desc::Reserved:
172         case L4::Kip::Mem_desc::Dedicated:
173         case L4::Kip::Mem_desc::Arch:
174         case L4::Kip::Mem_desc::Shared:
175         default:
176           break;
177         }
178     }
179
180   assert(max_addr > min_addr);
181   l4_addr_t total_pages = (max_addr - min_addr) >> L4_PAGESHIFT;
182
183   assert(total_pages);
184
185   pages = (typeof(pages))Single_page_alloc_base::_alloc(sizeof(*pages) * total_pages);
186
187   if (pages == 0)
188     {
189       Err(Err::Fatal).printf("could not allocate page array, halt\n");
190       exit(128);
191     }
192
193   memset(pages, 0, sizeof(*pages) * total_pages);
194
195   Moe::Pages::base_addr = min_addr;
196   Moe::Pages::max_addr  = max_addr;
197
198   info.printf("found RAM from %lx to %lx\n"
199               "allocated %ld KByte for the page array @%p\n",
200               min_addr, max_addr,
201               sizeof(*pages) * total_pages / 1024, pages);
202 }
203
204 static bool
205 init_utcb()
206 {
207   l4_utcb_t *u = l4_utcb();
208   boot.printf("UTCB @%p\n", u);
209   if (!u)
210     return false;
211
212   return true;
213 }
214
215 static void
216 init_kip_ds()
217 {
218   kip_ds = new Moe::Dataspace_static(const_cast<l4_kernel_info_t*>(kip()), L4_PAGESIZE, 0);
219   if (!kip_ds)
220     {
221       Err(Err::Fatal).printf("could not allocate dataspace for KIP!\n");
222       exit(1);
223     }
224
225   object_pool.cap_alloc()->alloc(kip_ds);
226 }
227
228
229 static void GC_CALLBACK finalization_notifier()
230 {
231   l4_msg_regs_t b;
232   l4_msg_regs_t *mr = l4_utcb_mr();
233   // GC_dump();
234   memcpy(&b, mr->mr, sizeof(l4_msg_regs_t));
235   GC_invoke_finalizers();
236   memcpy(mr->mr, &b, sizeof(l4_msg_regs_t));
237 }
238
239 class Loop_hooks :
240   public L4::Ipc_svr::Ignore_errors,
241   public L4::Ipc_svr::Default_timeout,
242   public L4::Ipc_svr::Compound_reply
243 {
244 public:
245   static void setup_wait(L4::Ipc_istream &istr, L4::Ipc_svr::Reply_mode)
246   {
247     GC_collect_a_little();
248     istr.reset();
249     istr << L4::Small_buf(Rcv_cap << L4_CAP_SHIFT,  L4_RCV_ITEM_LOCAL_ID);
250     l4_utcb_br_u(istr.utcb())->bdr = 0;
251   }
252 };
253
254 template< typename Reg >
255 class My_dispatcher
256 {
257 private:
258   Reg r;
259
260 public:
261   int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
262   {
263     l4_msgtag_t tag;
264     ios >> tag;
265     typename Reg::Value *o = 0;
266
267
268 #if 0
269     l4_utcb_t *u = l4_utcb();
270     L4::cout << L4::hex << "UTCB: " << u->values[0]
271       << "(" << op << "):" << u->values[1]
272       << "(" << obj << ")\n";
273 #endif
274
275     Dbg dbg(Dbg::Server);
276
277     dbg.printf("tag=%lx (proto=%lx) obj=%lx", tag.raw,
278                tag.label(), obj);
279
280     if (tag.is_exception())
281       {
282         dbg.cprintf("\n");
283         Dbg(Dbg::Exceptions).printf("unhandled exception...\n");
284         return -L4_ENOREPLY;
285       }
286     else
287       {
288         // L4::cout << "ROOT: CALL(" << (void*)obj<< "): " << op << "...\n";
289         o = r.find(obj & ~3UL);
290
291         // L4::cout << "ROOT: obj=" << o << "\n";
292
293         // enter_kdebug("a");
294
295         if (!o)
296           {
297             dbg.cprintf(": invalid object\n");
298             return -L4_ENOENT;
299           }
300
301         dbg.cprintf(": object is a %s\n", typeid(*o).name());
302         try
303           {
304             int res = o->dispatch(obj, ios);
305             dbg.printf("reply = %d\n", res);
306             return res;
307           }
308         catch (L4::Runtime_error &e)
309           {
310             int res = e.err_no();
311             dbg.printf("reply(excption) = %d\n", res);
312             return res;
313           }
314       }
315
316     Dbg(Dbg::Warn).printf("Invalid message (tag.label=%ld)\n", tag.label());
317     return -L4_ENOSYS;
318   }
319
320 };
321
322 static cxx::String _init_prog = "rom/ned";
323
324 struct Get_opt
325 {
326   char const *tag;
327   void (*hdl)(cxx::String const &);
328 };
329
330 struct Dbg_bits { char const *tag; unsigned long bits; };
331 static Dbg_bits const dbb[] =
332   {{"info",       Dbg::Info},
333    {"nfo",        Dbg::Info},
334    {"warn",       Dbg::Warn},
335    {"boot",       Dbg::Boot},
336    {"server",     Dbg::Server},
337    {"svr",        Dbg::Server},
338    {"exceptions", Dbg::Exceptions},
339    {"exc",        Dbg::Exceptions},
340    //{"POSIX",      0x40},
341    //{"ldso",       0x40},
342    {"loader",     Dbg::Loader},
343    {"ldr",        Dbg::Loader},
344    {"ns",         Dbg::Name_space},
345    {"all",        ~0UL},
346    {0,0}};
347
348 static Dbg_bits const ldr_flag_bits[] =
349   {{"pre_alloc",    L4RE_AUX_LDR_FLAG_EAGER_MAP},
350    {"eager_map",    L4RE_AUX_LDR_FLAG_EAGER_MAP},
351    {"all_segs_cow", L4RE_AUX_LDR_FLAG_ALL_SEGS_COW},
352    {"pinned_segs",  L4RE_AUX_LDR_FLAG_PINNED_SEGS},
353    {"exit",  0x10},
354    {0,0}};
355
356 static unsigned long parse_flags(cxx::String const &_args, Dbg_bits const *dbb,
357                                  cxx::String const &opt)
358 {
359   cxx::String args = _args;
360   unsigned long lvl = 0;
361   for (;;)
362     {
363       cxx::String::Index c = args.find(",|+");
364       cxx::String a = args.head(c);
365
366       if (a.empty())
367         break;
368
369       args = args.substr(c+1);
370       Dbg_bits const *b;
371
372       for (b = &dbb[0]; b->tag; ++b)
373         {
374           if (a == b->tag)
375             {
376               lvl |= b->bits;
377               break;
378             }
379         }
380
381       if (!b->tag)
382         {
383           warn.printf("ignore unkown argument for %.*s: '%.*s'\n",
384                       opt.len(), opt.start(), a.len(), a.start());
385
386         }
387     }
388   return lvl;
389 }
390
391 static void hdl_debug(cxx::String const &args)
392 {
393   unsigned long lvl = parse_flags(args, dbb, "--debug");
394   Dbg::level = lvl;
395 }
396
397 static void hdl_init(cxx::String const &args)
398 {
399   _init_prog = args;
400 }
401
402 static void hdl_l4re_dbg(cxx::String const &args)
403 {
404   unsigned long lvl = parse_flags(args, dbb, "--l4re-dbg");
405   Moe::l4re_dbg = lvl;
406 }
407
408 static void hdl_ldr_flags(cxx::String const &args)
409 {
410   unsigned long lvl = parse_flags(args, ldr_flag_bits, "--ldr-flags");
411   Moe::ldr_flags = lvl;
412 }
413
414
415
416 static Get_opt const _options[] = {
417       {"--debug=",     hdl_debug },
418       {"--init=",      hdl_init },
419       {"--l4re-dbg=",  hdl_l4re_dbg },
420       {"--ldr-flags=", hdl_ldr_flags },
421       {0, 0}
422 };
423
424 static void
425 parse_long_option(cxx::String const &o)
426 {
427
428   for (Get_opt const *opt = _options; opt->tag; ++opt)
429     {
430       if (o.starts_with(opt->tag))
431         {
432           opt->hdl(o.substr(strlen(opt->tag)));
433           return;
434         }
435     }
436
437   warn.printf("unknown command-line option '%.*s'\n", o.len(), o.start());
438 }
439
440 static void
441 parse_option(cxx::String const &o)
442 {
443   if (o.len() < 2)
444     {
445       warn.printf("empty command-line option '%.*s'\n", o.len(), o.start());
446       return;
447     }
448
449   if (o[1] == '-')
450     {
451       parse_long_option(o);
452       return;
453     }
454
455   for (cxx::String::Index s = o.start() + 1; !o.eof(s); ++s)
456     {
457       switch (o[s])
458         {
459         default:
460           warn.printf("unkown command-line option '%c'\n", o[s]);
461           break;
462         }
463     }
464
465
466 }
467
468 static Elf_loader elf_loader;
469
470 static L4::Server<Loop_hooks> server(l4_utcb());
471
472
473 static void init_env()
474 {
475   // setup log capability in the global env, so that the libc backend can use
476   // L4::Env::env()->log() to send logoutput to
477   l4re_global_env = reinterpret_cast<l4re_env_t*>(&my_env);
478   my_env.factory(L4_BASE_FACTORY_CAP);
479   my_env.log(L4_BASE_LOG_CAP);
480   my_env.scheduler(L4_BASE_SCHEDULER_CAP);
481 }
482
483 static __attribute__((used,section(".preinit_array")))
484    const void *pre_init_env = (void *)init_env;
485
486 int main(int argc, char**argv)
487 {
488   (void)argc; (void)argv;
489   Dbg::set_level(Dbg::Info | Dbg::Warn);
490   //Dbg::level |= Dbg::Boot;
491
492   info.printf("Hello world\n");
493
494     {
495       using L4Re::Env;
496       Env::env()->scheduler()->run_thread(L4::Cap<L4::Thread>(L4_BASE_THREAD_CAP), l4_sched_param(0xff));
497     }
498
499 #if 0 // map RO stuff RO, we'll see write pagefaults if someone write to our
500       // RO segments later on
501   extern char _stext[];
502   extern char _etext[];
503
504   for (unsigned long i = (unsigned long)_stext; i < (unsigned long)_etext; i+= L4_PAGESIZE)
505     {
506       l4_task_unmap(l4_utcb(), L4_BASE_TASK_CAP, l4_fpage(i, L4_PAGESHIFT, L4_FPAGE_W), L4_FP_ALL_SPACES);
507     }
508 #endif
509
510   try
511     {
512       map_kip();
513       init_utcb();
514       Moe::Boot_fs::init_stage1();
515       find_memory();
516 #if 0
517       extern unsigned page_alloc_debug;
518       page_alloc_debug = 1;
519 #endif
520       GC_set_dont_expand(1);
521       GC_set_finalizer_notifier(finalization_notifier);
522       GC_set_finalize_on_demand(1);
523
524       Moe::Boot_fs::init_stage2();
525       init_vesa_fb((l4util_mb_info_t*)kip()->user_ptr);
526
527       root_name_space_obj = object_pool.cap_alloc()->alloc(root_name_space());
528
529       init_kip_ds();
530       Region_map::init_limits();
531
532       object_pool.cap_alloc()->alloc(Allocator::root_allocator());
533
534       l4_debugger_set_object_name(L4_BASE_TASK_CAP,   "moe");
535       l4_debugger_set_object_name(L4_BASE_THREAD_CAP, "moe");
536       l4_debugger_set_object_name(L4_BASE_PAGER_CAP,  "moe->s0");
537
538       root_name_space()->register_obj("log", Obj(Obj::F_rw, L4_BASE_LOG_CAP));
539       root_name_space()->register_obj("icu", Obj(Obj::F_rw, L4_BASE_ICU_CAP));
540       root_name_space()->register_obj("sigma0", Obj(Obj::F_trusted | Obj::F_rw, L4_BASE_PAGER_CAP));
541       root_name_space()->register_obj("mem", Obj(Obj::F_trusted | Obj::F_rw, Allocator::root_allocator()));
542
543       char *cmdline = my_cmdline();
544
545       info.printf("cmdline: %s\n", cmdline);
546
547       bool skip_argv0 = true;
548       cxx::Pair<cxx::String, cxx::String> a;
549       for (a = next_arg(cmdline); !a.first.empty(); a = next_arg(a.second))
550         {
551           if (skip_argv0)
552             {
553               skip_argv0 = false;
554               continue;
555             }
556
557           if (a.first[0] != '-') // not an option start init
558             {
559               elf_loader.start(_init_prog, cxx::String(a.first.start(), a.second.end()));
560               break;
561             }
562
563           if (a.first == "--")
564             {
565               elf_loader.start(_init_prog, a.second);
566               break;
567             }
568
569           parse_option(a.first);
570         }
571
572       if (a.first.empty())
573         elf_loader.start(_init_prog, cxx::String(""));
574
575       // dump name space information
576       if (boot.is_active())
577         {
578           boot.printf("dump of root name space:\n");
579           root_name_space()->dump(1);
580         }
581
582       // we handle our exceptions ourselves
583       server.loop_noexc(My_dispatcher<L4::Basic_registry>());
584     }
585   catch (L4::Out_of_memory const &e)
586     {
587       Err(Err::Fatal).printf("Memory exhausted and not handled\n");
588       L4::cerr << "FATAL exception in MOE:\n"
589                << e << "... terminated\n";
590     }
591   catch (L4::Runtime_error const &e)
592     {
593       L4::cerr << "FATAL exception in MOE:\n"
594                << e << "... terminated\n";
595       abort();
596     }
597   return 0;
598 }
599