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