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