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