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/assert.h>
16 #include <l4/sys/kip>
17 #include <l4/sys/utcb.h>
18 #include <l4/sys/debugger.h>
19 #include <l4/sys/scheduler>
20 #include <l4/sys/thread>
21 #include <l4/sys/cxx/ipc_server_loop>
22 #include <l4/re/error_helper>
23 
24 #include <l4/cxx/exceptions>
25 #include <l4/cxx/iostream>
26 #include <l4/cxx/l4iostream>
27 
28 #include <l4/util/l4mod.h>
29 #include <typeinfo>
30 
31 #include <cctype>
32 #include <cstdlib>
33 #include <cstring>
34 #include <cstdio>
35 
36 #include "boot_fs.h"
37 #include "globals.h"
38 #include "loader_elf.h"
39 #include "log.h"
40 #include "name_space.h"
41 #include "page_alloc.h"
42 #include "pages.h"
43 #include "vesa_fb.h"
44 #include "dataspace_static.h"
45 #include "debug.h"
46 #include "args.h"
47 
48 #include <l4/re/env>
49 
50 using Moe::Entry;
51 
52 static L4Re::Env my_env;
53 
54 // Implementation
55 extern "C" void _exit(int status);
56 
_exit(int status)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
map_kip()72 l4_kernel_info_t const *map_kip()
73 {
74   // map the KIP 1:1, because moe has 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
my_cmdline()89 char *my_cmdline()
90 {
91   l4util_l4mod_info const *_mbi_ = (l4util_l4mod_info const *)kip()->user_ptr;
92   boot.printf("mbi @%p\n", _mbi_);
93   l4util_l4mod_mod const *modules = (l4util_l4mod_mod const *)_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 ((modules[mod].flags & L4util_l4mod_mod_flag_mask) == L4util_l4mod_mod_flag_roottask)
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 
find_memory()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   for (auto const &md: L4::Kip::Mem_desc::all(kip()))
154     {
155       if (md.is_virtual())
156         continue;
157 
158       L4::Kip::Mem_desc::Mem_type type = md.type();
159       unsigned long end = l4_round_page(md.end());
160       unsigned long start = l4_trunc_page(md.start());
161       switch (type)
162         {
163         case L4::Kip::Mem_desc::Bootloader:
164           if (start < min_addr)
165             min_addr = start;
166           if (end > max_addr)
167             max_addr = end;
168           break;
169         case L4::Kip::Mem_desc::Conventional:
170         case L4::Kip::Mem_desc::Reserved:
171         case L4::Kip::Mem_desc::Dedicated:
172         case L4::Kip::Mem_desc::Arch:
173         case L4::Kip::Mem_desc::Shared:
174         default:
175           break;
176         }
177     }
178 
179   assert(max_addr > min_addr);
180   l4_addr_t total_pages = (max_addr - min_addr) >> L4_PAGESHIFT;
181 
182   assert(total_pages);
183 
184   pages = (__typeof(pages))Single_page_alloc_base::_alloc(sizeof(*pages) * total_pages);
185 
186   if (pages == 0)
187     {
188       Err(Err::Fatal).printf("could not allocate page array, halt\n");
189       exit(128);
190     }
191 
192   memset(pages, 0, sizeof(*pages) * total_pages);
193 
194   Moe::Pages::base_addr = min_addr;
195   Moe::Pages::max_addr  = max_addr;
196 
197   info.printf("found RAM from %lx to %lx\n",
198               min_addr, max_addr);
199   info.printf("allocated %ld KByte for the page array @%p\n",
200               sizeof(*pages) * total_pages / 1024, pages);
201 }
202 
203 l4_addr_t Moe::Virt_limit::start;
204 l4_addr_t Moe::Virt_limit::end;
205 
206 static void
init_virt_limits()207 init_virt_limits()
208 {
209   for (auto const &m: L4::Kip::Mem_desc::all(kip()))
210     {
211       if (m.type() != L4::Kip::Mem_desc::Conventional || !m.is_virtual())
212         continue;
213 
214       Moe::Virt_limit::start = m.start();
215       Moe::Virt_limit::end = m.end();
216     }
217 
218   info.printf("virtual user address space [%lx-%lx]\n",
219               Moe::Virt_limit::start,
220               Moe::Virt_limit::end);
221 }
222 
223 static void
init_utcb()224 init_utcb()
225 {
226   l4_utcb_t *u = l4_utcb();
227   boot.printf("UTCB @%p\n", u);
228   if (!u)
229     abort();
230 }
231 
232 static void
init_kip_ds()233 init_kip_ds()
234 {
235   kip_ds = new Moe::Dataspace_static(const_cast<l4_kernel_info_t *>(kip()),
236                                      L4_PAGESIZE, L4Re::Dataspace::F::RX);
237   if (!kip_ds)
238     {
239       Err(Err::Fatal).printf("could not allocate dataspace for KIP!\n");
240       exit(1);
241     }
242 
243   object_pool.cap_alloc()->alloc(kip_ds);
244 }
245 
246 static L4::Cap<void>
new_sigma0_cap()247 new_sigma0_cap()
248 {
249   L4::Cap<void> new_sigma0_cap = object_pool.cap_alloc()->alloc();
250 
251   L4Re::chksys(
252     L4::Cap<L4::Factory>(Sigma0_cap)->create(new_sigma0_cap, L4_PROTO_SIGMA0),
253     "Create new sigma0 cap for the initial task.");
254 
255   return new_sigma0_cap;
256 }
257 
258 class Loop_hooks :
259   public L4::Ipc_svr::Ignore_errors,
260   public L4::Ipc_svr::Default_timeout,
261   public L4::Ipc_svr::Compound_reply
262 {
263 public:
setup_wait(l4_utcb_t * utcb,L4::Ipc_svr::Reply_mode)264   static void setup_wait(l4_utcb_t *utcb, L4::Ipc_svr::Reply_mode)
265   {
266     l4_utcb_br_u(utcb)->br[0] = L4::Ipc::Small_buf(Rcv_cap << L4_CAP_SHIFT,
267                                                    L4_RCV_ITEM_LOCAL_ID).raw();
268     l4_utcb_br_u(utcb)->br[1] = 0;
269     l4_utcb_br_u(utcb)->bdr = 0;
270   }
271 };
272 
273 template< typename Reg >
274 class My_dispatcher
275 {
276 private:
277   Reg r;
278 
279 public:
dispatch(l4_msgtag_t tag,l4_umword_t obj,l4_utcb_t * utcb)280   l4_msgtag_t dispatch(l4_msgtag_t tag, l4_umword_t obj, l4_utcb_t *utcb)
281   {
282     typename Reg::Value *o = 0;
283 
284 #if 0
285     l4_utcb_t *u = l4_utcb();
286     L4::cout << L4::hex << "UTCB: " << u->values[0]
287       << "(" << op << "):" << u->values[1]
288       << "(" << obj << ")\n";
289 #endif
290 
291     Dbg dbg(Dbg::Server);
292 
293     dbg.printf("tag=%lx (proto=%lx) obj=%lx", tag.raw,
294                tag.label(), obj);
295 
296     if (tag.is_exception())
297       {
298         dbg.cprintf("\n");
299         Dbg(Dbg::Exceptions).printf("unhandled exception...\n");
300         return l4_msgtag(-L4_ENOREPLY, 0, 0, 0);
301       }
302     else
303       {
304         // L4::cout << "ROOT: CALL(" << (void*)obj<< "): " << op << "...\n";
305         o = r.find(obj & ~3UL);
306 
307         // L4::cout << "ROOT: obj=" << o << "\n";
308 
309         // enter_kdebug("a");
310 
311         if (!o)
312           {
313             dbg.cprintf(": invalid object\n");
314             return l4_msgtag(-L4_ENOENT, 0, 0, 0);
315           }
316 
317         dbg.cprintf(": object is a %s\n", typeid(*o).name());
318         try
319           {
320             l4_msgtag_t res = o->dispatch(tag, obj, utcb);
321             dbg.printf("reply = %ld\n", res.label());
322             return res;
323           }
324         catch (L4::Runtime_error &e)
325           {
326             int res = e.err_no();
327             dbg.printf("reply(exception) = %d\n", res);
328             return l4_msgtag(res, 0, 0, 0);
329           }
330       }
331 
332     Dbg(Dbg::Warn).printf("Invalid message (tag.label=%ld)\n", tag.label());
333     return l4_msgtag(-L4_ENOSYS, 0, 0, 0);
334   }
335 
336 };
337 
338 static cxx::String _init_prog = "rom/ned";
339 
340 struct Get_opt
341 {
342   char const *tag;
343   void (*hdl)(cxx::String const &);
344 };
345 
346 struct Dbg_bits { char const *tag; unsigned long bits; };
347 static Dbg_bits const dbb[] =
348   {{"info",       Dbg::Info},
349    {"nfo",        Dbg::Info},
350    {"warn",       Dbg::Warn},
351    {"boot",       Dbg::Boot},
352    {"server",     Dbg::Server},
353    {"svr",        Dbg::Server},
354    {"exceptions", Dbg::Exceptions},
355    {"exc",        Dbg::Exceptions},
356    //{"POSIX",      0x40},
357    //{"ldso",       0x40},
358    {"loader",     Dbg::Loader},
359    {"ldr",        Dbg::Loader},
360    {"ns",         Dbg::Name_space},
361    {"all",        ~0UL},
362    {0, 0}};
363 
364 static Dbg_bits const ldr_flag_bits[] =
365   {{"pre_alloc",    L4RE_AUX_LDR_FLAG_EAGER_MAP},
366    {"eager_map",    L4RE_AUX_LDR_FLAG_EAGER_MAP},
367    {"all_segs_cow", L4RE_AUX_LDR_FLAG_ALL_SEGS_COW},
368    {"pinned_segs",  L4RE_AUX_LDR_FLAG_PINNED_SEGS},
369    {"exit",  0x10},
370    {0, 0}};
371 
parse_flags(cxx::String const & _args,Dbg_bits const * dbb,cxx::String const & opt)372 static unsigned long parse_flags(cxx::String const &_args, Dbg_bits const *dbb,
373                                  cxx::String const &opt)
374 {
375   cxx::String args = _args;
376   unsigned long lvl = 0;
377   for (;;)
378     {
379       cxx::String::Index c = args.find(",|+");
380       cxx::String a = args.head(c);
381 
382       if (a.empty())
383         break;
384 
385       args = args.substr(c+1);
386       Dbg_bits const *b;
387 
388       for (b = &dbb[0]; b->tag; ++b)
389         {
390           if (a == b->tag)
391             {
392               lvl |= b->bits;
393               break;
394             }
395         }
396 
397       if (!b->tag)
398         {
399           warn.printf("ignore unknown argument for %.*s: '%.*s'\n",
400                       opt.len(), opt.start(), a.len(), a.start());
401 
402         }
403     }
404   return lvl;
405 }
406 
hdl_debug(cxx::String const & args)407 static void hdl_debug(cxx::String const &args)
408 {
409   Dbg::set_level(parse_flags(args, dbb, "--debug"));
410 }
411 
hdl_init(cxx::String const & args)412 static void hdl_init(cxx::String const &args)
413 {
414   _init_prog = args;
415 }
416 
hdl_l4re_dbg(cxx::String const & args)417 static void hdl_l4re_dbg(cxx::String const &args)
418 {
419   unsigned long lvl = parse_flags(args, dbb, "--l4re-dbg");
420   Moe::l4re_dbg = lvl;
421 }
422 
hdl_ldr_flags(cxx::String const & args)423 static void hdl_ldr_flags(cxx::String const &args)
424 {
425   unsigned long lvl = parse_flags(args, ldr_flag_bits, "--ldr-flags");
426   Moe::ldr_flags = lvl;
427 }
428 
429 
430 
431 static Get_opt const _options[] = {
432       {"--debug=",     hdl_debug },
433       {"--init=",      hdl_init },
434       {"--l4re-dbg=",  hdl_l4re_dbg },
435       {"--ldr-flags=", hdl_ldr_flags },
436       {0, 0}
437 };
438 
439 static void
parse_long_option(cxx::String const & o)440 parse_long_option(cxx::String const &o)
441 {
442 
443   for (Get_opt const *opt = _options; opt->tag; ++opt)
444     {
445       if (o.starts_with(opt->tag))
446         {
447           opt->hdl(o.substr(strlen(opt->tag)));
448           return;
449         }
450     }
451 
452   warn.printf("unknown command-line option '%.*s'\n", o.len(), o.start());
453 }
454 
455 static void
parse_option(cxx::String const & o)456 parse_option(cxx::String const &o)
457 {
458   if (o.len() < 2)
459     {
460       warn.printf("empty command-line option '%.*s'\n", o.len(), o.start());
461       return;
462     }
463 
464   if (o[1] == '-')
465     {
466       parse_long_option(o);
467       return;
468     }
469 
470   for (cxx::String::Index s = o.start() + 1; !o.eof(s); ++s)
471     {
472       switch (o[s])
473         {
474         default:
475           warn.printf("unknown command-line option '%c'\n", o[s]);
476           break;
477         }
478     }
479 }
480 
481 static Elf_loader elf_loader;
482 
483 static L4::Server<Loop_hooks> server;
484 
485 
init_env()486 static void init_env()
487 {
488   // setup log capability in the global env, so that the libc backend can use
489   // L4::Env::env()->log() to send logoutput to
490   l4re_global_env = reinterpret_cast<l4re_env_t*>(&my_env);
491   my_env.factory(L4_BASE_FACTORY_CAP);
492   my_env.log(L4_BASE_LOG_CAP);
493   my_env.scheduler(L4_BASE_SCHEDULER_CAP);
494 }
495 
496 static __attribute__((used, section(".preinit_array")))
497    const void *pre_init_env = (void *)init_env;
498 
init_emergency_memory()499 static void init_emergency_memory()
500 {
501   // populate the page allocator with a few pages of static memory to allow for
502   // dynamic allocation of memory arena during static initialization of stdc++'s
503   // emergency_pool in GCC versions 5 and newer
504   static __attribute__((aligned(L4_PAGESIZE))) char buf[3 * L4_PAGESIZE];
505   Single_page_alloc_base::_free(buf, sizeof(buf), true);
506   // make sure the emergency memory is RWX for future reuse
507   int err = l4sigma0_map_mem(Sigma0_cap, (l4_addr_t) buf, (l4_addr_t) buf,
508                              sizeof(buf));
509   l4_assert(!err);
510   (void)err;
511 }
512 
513 static __attribute__((used, section(".preinit_array")))
514    const void *pre_init_emergency_memory = (void *)init_emergency_memory;
515 
main(int argc,char ** argv)516 int main(int argc, char**argv)
517 {
518   (void)argc; (void)argv;
519   Dbg::set_level(Dbg::Info | Dbg::Warn);
520   //Dbg::set_level(Dbg::Info | Dbg::Warn | Dbg::Boot);
521 
522   info.printf("Hello world\n");
523 
524   L4Re::Env::env()->scheduler()
525     ->run_thread(L4::Cap<L4::Thread>(L4_BASE_THREAD_CAP), l4_sched_param(0xff));
526 
527 #if 0 // map RO stuff RO, we'll see write pagefaults if someone write to our
528       // RO segments later on
529   extern char _stext[];
530   extern char _etext[];
531 
532   for (unsigned long i = (unsigned long)_stext; i < (unsigned long)_etext;
533        i+= L4_PAGESIZE)
534     {
535       l4_task_unmap(l4_utcb(), L4_BASE_TASK_CAP,
536                     l4_fpage(i, L4_PAGESHIFT, L4_FPAGE_W), L4_FP_ALL_SPACES);
537     }
538 #endif
539 
540   try
541     {
542       map_kip();
543       init_utcb();
544       Moe::Boot_fs::init_stage1();
545       find_memory();
546       init_virt_limits();
547 #if 0
548       extern unsigned page_alloc_debug;
549       page_alloc_debug = 1;
550 #endif
551       Moe::Boot_fs::init_stage2();
552       init_vesa_fb((l4util_l4mod_info *)kip()->user_ptr);
553 
554       root_name_space_obj = object_pool.cap_alloc()->alloc(root_name_space());
555 
556       init_kip_ds();
557 
558       object_pool.cap_alloc()->alloc(Allocator::root_allocator());
559 
560       l4_debugger_set_object_name(L4_BASE_TASK_CAP,   "moe");
561       l4_debugger_set_object_name(L4_BASE_THREAD_CAP, "moe");
562       l4_debugger_set_object_name(L4_BASE_PAGER_CAP,  "moe->s0");
563 
564       root_name_space()->register_obj("log", Entry::F_rw, L4_BASE_LOG_CAP);
565       root_name_space()->register_obj("icu", Entry::F_rw, L4_BASE_ICU_CAP);
566       if (L4::Cap<void>(L4_BASE_IOMMU_CAP).validate().label())
567         root_name_space()->register_obj("iommu", Entry::F_rw, L4_BASE_IOMMU_CAP);
568       if (L4::Cap<void>(L4_BASE_ARM_SMCCC_CAP).validate().label())
569         root_name_space()->register_obj("arm_smc", Entry::F_rw, L4_BASE_ARM_SMCCC_CAP);
570       root_name_space()->register_obj("sigma0", Entry::F_trusted | Entry::F_rw,
571                                       new_sigma0_cap());
572       root_name_space()->register_obj("mem", Entry::F_trusted | Entry::F_rw, Allocator::root_allocator());
573       if (L4::Cap<void>(L4_BASE_DEBUGGER_CAP).validate().label())
574         root_name_space()->register_obj("jdb", Entry::F_trusted | Entry::F_rw, L4_BASE_DEBUGGER_CAP);
575       root_name_space()->register_obj("kip", Entry::F_rw, kip_ds->obj_cap());
576 
577       char *cmdline = my_cmdline();
578 
579       info.printf("cmdline: %s\n", cmdline);
580 
581       bool skip_argv0 = true;
582       cxx::Pair<cxx::String, cxx::String> a;
583       for (a = next_arg(cmdline); !a.first.empty(); a = next_arg(a.second))
584         {
585           if (skip_argv0)
586             {
587               skip_argv0 = false;
588               continue;
589             }
590 
591           if (a.first[0] != '-') // not an option start init
592             {
593               elf_loader.start(_init_prog, cxx::String(a.first.start(),
594                                                        a.second.end()));
595               break;
596             }
597 
598           if (a.first == "--")
599             {
600               elf_loader.start(_init_prog, a.second);
601               break;
602             }
603 
604           parse_option(a.first);
605         }
606 
607       if (a.first.empty())
608         elf_loader.start(_init_prog, cxx::String(""));
609 
610       // dump name space information
611       if (boot.is_active())
612         {
613           boot.printf("dump of root name space:\n");
614           root_name_space()->dump(1);
615         }
616 
617       // we handle our exceptions ourselves
618       server.loop_noexc(My_dispatcher<L4::Basic_registry>());
619     }
620   catch (L4::Out_of_memory const &e)
621     {
622       Err(Err::Fatal).printf("Memory exhausted and not handled\n");
623       L4::cerr << "FATAL exception in MOE:\n"
624                << e << "... terminated\n";
625     }
626   catch (L4::Runtime_error const &e)
627     {
628       L4::cerr << "FATAL exception in MOE:\n"
629                << e << "... terminated\n";
630       abort();
631     }
632   return 0;
633 }
634