]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/bootstrap/server/src/startup.cc
6aee7c3dcf92745491f4699198e5cfd9ff62313b
[l4.git] / l4 / pkg / bootstrap / server / src / startup.cc
1 /**
2  * \file        bootstrap/server/src/startup.c
3  * \brief       Main functions
4  *
5  * \date        09/2004
6  * \author      Torsten Frenzel <frenzel@os.inf.tu-dresden.de>,
7  *              Frank Mehnert <fm3@os.inf.tu-dresden.de>,
8  *              Adam Lackorzynski <adam@os.inf.tu-dresden.de>
9  *              Alexander Warg <aw11@os.inf.tu-dresden.de>
10  *              Sebastian Sumpf <sumpf@os.inf.tu-dresden.de>
11  */
12
13 /*
14  * (c) 2005-2009 Author(s)
15  *     economic rights: Technische Universität Dresden (Germany)
16  *
17  * This file is part of TUD:OS and distributed under the terms of the
18  * GNU General Public License 2.
19  * Please see the COPYING-GPL-2 file for details.
20  */
21
22 /* LibC stuff */
23 #ifndef _GNU_SOURCE
24 #define _GNU_SOURCE
25 #endif
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <ctype.h>
31
32 /* L4 stuff */
33 #include <l4/sys/compiler.h>
34 #include <l4/util/mb_info.h>
35 #include <l4/util/l4_macros.h>
36 #include "panic.h"
37
38 /* local stuff */
39 #include "exec.h"
40 #include "macros.h"
41 #include "region.h"
42 #include "module.h"
43 #include "startup.h"
44 #include "support.h"
45 #include "init_kip.h"
46 #include "patch.h"
47 #include "loader_mbi.h"
48 #include "startup.h"
49 #if defined (ARCH_x86) || defined(ARCH_amd64)
50 #include "ARCH-x86/serial.h"
51 #endif
52
53 #if defined (ARCH_ppc32)
54 #include <l4/drivers/of_if.h>
55 #include <l4/drivers/of_dev.h>
56 #endif
57
58 #undef getchar
59
60 static l4util_mb_info_t *mb_info;
61 /* management of allocated memory regions */
62 static Region_list regions;
63 static Region __regs[MAX_REGION];
64
65 /* management of conventional memory regions */
66 static Region_list ram;
67 static Region __ram[8];
68
69 #if defined(ARCH_x86) || defined(ARCH_amd64)
70 static l4util_mb_vbe_mode_t __mb_vbe;
71 static l4util_mb_vbe_ctrl_t __mb_ctrl;
72 #endif
73
74 l4_kip_kernel_uart_info kip_kernel_uart_info;
75
76 /*
77  * IMAGE_MODE means that all boot modules are linked together to one
78  * big binary.
79  */
80 #ifdef IMAGE_MODE
81 static l4_addr_t _mod_addr = RAM_BASE + MODADDR;
82 #else
83 static l4_addr_t _mod_addr;
84 #endif
85
86 static const char *builtin_cmdline = CMDLINE;
87
88 /* modules to load by bootstrap */
89 static int sigma0 = 1;   /* we need sigma0 */
90 static int roottask = 1; /* we need a roottask */
91
92 enum {
93   kernel_module,
94   sigma0_module,
95   roottask_module,
96 };
97
98 /* we define a small stack for sigma0 and roottask here -- it is used by L4
99  * for parameter passing. however, sigma0 and roottask must switch to its
100  * own private stack as soon as it has initialized itself because this memory
101  * region is later recycled in init.c */
102 static char roottask_init_stack[64]; /* XXX hardcoded */
103 static char sigma0_init_stack[64]; /* XXX hardcoded */
104
105
106 static exec_handler_func_t l4_exec_read_exec;
107 static exec_handler_func_t l4_exec_add_region;
108
109
110 #if 0
111 static void
112 dump_mbi(l4util_mb_info_t *mbi)
113 {
114   printf("%p-%p\n", (void*)(mbi->mem_lower << 10), (void*)(mbi->mem_upper << 10));
115   printf("MBI:     [%p-%p]\n", mbi, mbi + 1);
116   printf("MODINFO: [%p-%p]\n", (char*)mbi->mods_addr,
117       (l4util_mb_mod_t*)(mbi->mods_addr) + mbi->mods_count);
118
119   printf("VBEINFO: [%p-%p]\n", (char*)mbi->vbe_ctrl_info,
120       (l4util_mb_vbe_ctrl_t*)(mbi->vbe_ctrl_info) + 1);
121   printf("VBEMODE: [%p-%p]\n", (char*)mbi->vbe_mode_info,
122       (l4util_mb_vbe_mode_t*)(mbi->vbe_mode_info) + 1);
123
124   l4util_mb_mod_t *m = (l4util_mb_mod_t*)(mbi->mods_addr);
125   l4util_mb_mod_t *me = m + mbi->mods_count;
126   for (; m < me; ++m)
127     {
128       printf("  MOD: [%p-%p]\n", (void*)m->mod_start, (void*)m->mod_end);
129       printf("  CMD: [%p-%p]\n", (char*)m->cmdline,
130           (char*)m->cmdline + strlen((char*)m->cmdline));
131     }
132 }
133 #endif
134
135
136 /**
137  * Scan the memory regions with type == Region::Kernel for a
138  * kernel interface page (KIP).
139  *
140  * After loading the kernel we scan for the magic number at page boundaries.
141  */
142 static
143 void *find_kip()
144 {
145   unsigned char *p, *end;
146   void *k = 0;
147
148   printf("  find kernel info page...\n");
149   for (Region const *m = regions.begin(); m != regions.end(); ++m)
150     {
151       if (m->type() != Region::Kernel)
152         continue;
153
154       if (sizeof(unsigned long) < 8
155           && m->end() >= (1ULL << 32))
156         end = (unsigned char *)(~0UL - 0x1000);
157       else
158         end = (unsigned char *) (unsigned long)m->end();
159
160       for (p = (unsigned char *) (unsigned long)(m->begin() & 0xfffff000);
161            p < end;
162            p += 0x1000)
163         {
164           l4_umword_t magic = L4_KERNEL_INFO_MAGIC;
165           if (memcmp(p, &magic, 4) == 0)
166             {
167               k = p;
168               printf("  found kernel info page at %p\n", p);
169               break;
170             }
171         }
172     }
173
174   if (!k)
175     panic("could not find kernel info page, maybe your kernel is too old");
176
177   return k;
178 }
179
180 const char *get_cmdline(l4util_mb_info_t *mbi)
181 {
182   if (mbi && mbi->flags & L4UTIL_MB_CMDLINE)
183     return L4_CHAR_PTR(mbi->cmdline);
184
185   if (*builtin_cmdline)
186     return builtin_cmdline;
187
188   return 0;
189 }
190
191 /**
192  * Get the API version from the KIP.
193  */
194 static inline
195 unsigned long get_api_version(void *kip)
196 {
197   return ((unsigned long *)kip)[1];
198 }
199
200
201 static char *
202 check_arg_str(char *cmdline, const char *arg)
203 {
204   char *s = cmdline;
205   while ((s = strstr(s, arg)))
206     {
207       if (s == cmdline
208           || isspace(s[-1]))
209         return s;
210     }
211   return NULL;
212 }
213
214 /**
215  * Scan the command line for the given argument.
216  *
217  * The cmdline string may either be including the calling program
218  * (.../bootstrap -arg1 -arg2) or without (-arg1 -arg2) in the realmode
219  * case, there, we do not have a leading space
220  *
221  * return pointer after argument, NULL if not found
222  */
223 static char *
224 check_arg(l4util_mb_info_t *mbi, const char *arg)
225 {
226   const char *c = get_cmdline(mbi);
227   if (c)
228     return check_arg_str((char *)c, arg);
229
230   return NULL;
231 }
232
233
234 /**
235  * Calculate the maximum memory limit in MB.
236  *
237  * The limit is the highes physical address where conventional RAM is allowed.
238  *
239  * If available the '-maxmem=xx' command line option is used.
240  * If not then the memory is limited to 3 GB IA32 and unlimited on other
241  * systems.
242  */
243 static
244 unsigned long
245 get_memory_limit(l4util_mb_info_t *mbi)
246 {
247   unsigned long arch_limit = ~0UL;
248 #if defined(ARCH_x86)
249   /* Limit memory, we cannot really handle more right now. In fact, the
250    * problem is roottask. It maps as many superpages/pages as it gets.
251    * After that, the remaining pages are mapped using l4sigma0_map_anypage()
252    * with a receive window of L4_WHOLE_ADDRESS_SPACE. In response Sigma0
253    * could deliver pages beyond the 3GB user space limit. */
254   arch_limit = 3024UL << 20;
255 #endif
256
257   /* maxmem= parameter? */
258   if (char *c = check_arg(mbi, "-maxmem="))
259     {
260       unsigned long l = strtoul(c + 8, NULL, 10) << 20;
261       if (l < arch_limit)
262         return l;
263     }
264
265   return arch_limit;
266 }
267
268 static int
269 parse_memvalue(const char *s, unsigned long *val, char **ep)
270 {
271
272   *val = strtoul(s, ep, 0);
273   if (*val == ~0UL)
274     return 1;
275
276   switch (**ep)
277     {
278     case 'G': *val <<= 10;
279     case 'M': *val <<= 10;
280     case 'k': case 'K': *val <<= 10; (*ep)++;
281     };
282
283   return 0;
284 }
285
286 /*
287  * Parse a memory layout string: size@offset
288  * E.g.: 256M@0x40000000, or 128M@128M
289  */
290 static int
291 parse_mem_layout(const char *s, unsigned long *sz, unsigned long *offset)
292 {
293   char *ep;
294
295   if (parse_memvalue(s, sz, &ep))
296     return 1;
297
298   if (*sz == 0)
299     return 1;
300
301   if (*ep != '@')
302     return 1;
303
304   if (parse_memvalue(ep + 1, offset, &ep))
305     return 1;
306
307   return 0;
308 }
309
310 static void
311 dump_ram_map(bool show_total = false)
312 {
313   // print RAM summary
314   unsigned long long sum = 0;
315   for (Region *i = ram.begin(); i < ram.end(); ++i)
316     {
317       printf("  RAM: %016llx - %016llx: %lldkB\n",
318              i->begin(), i->end(), (i->end() - i->begin() + 1) >> 10);
319       sum += i->end() - i->begin() + 1;
320     }
321   if (show_total)
322     printf("  Total RAM: %lldMB\n", sum >> 20);
323 }
324
325 static void
326 setup_memory_map(l4util_mb_info_t *mbi)
327 {
328   bool parsed_mem_option = false;
329   const char *s = get_cmdline(mbi);
330
331   if (s)
332     {
333       while ((s = check_arg_str((char *)s, "-mem=")))
334         {
335           s += 5;
336           unsigned long sz, offset = 0;
337           if (!parse_mem_layout(s, &sz, &offset))
338             {
339               parsed_mem_option = true;
340               ram.add(Region::n(offset, offset + sz, ".ram", Region::Ram));
341             }
342         }
343     }
344
345   if (!parsed_mem_option)
346     // No -mem option given, use the one given by the platform
347     Platform_base::platform->setup_memory_map(mbi, &ram, &regions);
348
349   dump_ram_map(true);
350 }
351
352 static void do_the_memset(unsigned long s, unsigned val, unsigned long len)
353 {
354   printf("Presetting memory %16lx - %16lx to '%x'\n",
355          s, s + len - 1, val);
356   memset((void *)s, val, len);
357 }
358
359 static void fill_mem(unsigned fill_value)
360 {
361   regions.sort();
362   for (Region const *r = ram.begin(); r != ram.end(); ++r)
363     {
364       unsigned long long b = r->begin();
365       // The regions list must be sorted!
366       for (Region const *reg = regions.begin(); reg != regions.end(); ++reg)
367         {
368           // completely before ram?
369           if (reg->end() < r->begin())
370             continue;
371           // completely after ram?
372           if (reg->begin() > r->end())
373             break;
374
375           if (reg->begin() <= r->begin())
376             b = reg->end() + 1;
377           else if (b > reg->begin()) // some overlapping
378             {
379               if (reg->end() + 1 > b)
380                 b = reg->end() + 1;
381             }
382           else
383             {
384               do_the_memset(b, fill_value, reg->begin() - 1 - b + 1);
385               b = reg->end() + 1;
386             }
387         }
388
389       if (b < r->end())
390         do_the_memset(b, fill_value, r->end() - b + 1);
391     }
392 }
393
394
395 /**
396  * Move modules to another address.
397  *
398  * Source and destination regions may overlap.
399  */
400 static void
401 move_modules(l4util_mb_info_t *mbi, unsigned long modaddr)
402 {
403   long offset = modaddr - (L4_MB_MOD_PTR(mbi->mods_addr))[0].mod_start;
404   unsigned i;
405   unsigned dir = offset > 0 ? mbi->mods_count : 1;
406
407   if (!offset)
408     {
409       printf("  => Images in place\n");
410       return;
411     }
412
413   printf("  move modules to %lx with offset %lx\n", modaddr, offset);
414
415   for (i = dir; i != mbi->mods_count - dir ; offset > 0 ? i-- : i++)
416     {
417       unsigned long start = (L4_MB_MOD_PTR(mbi->mods_addr))[i-1].mod_start;
418       unsigned long end = (L4_MB_MOD_PTR(mbi->mods_addr))[i-1].mod_end;
419
420       if (start == end)
421         continue;
422
423 #ifdef VERBOSE_LOAD
424       unsigned char c[5];
425       c[0] = *(unsigned char*)(start + 0);
426       c[1] = *(unsigned char*)(start + 1);
427       c[2] = *(unsigned char*)(start + 2);
428       c[3] = *(unsigned char*)(start + 3);
429       c[4] = 0;
430       c[0] = c[0] < 32 ? '.' : c[0];
431       c[1] = c[1] < 32 ? '.' : c[1];
432       c[2] = c[2] < 32 ? '.' : c[2];
433       c[3] = c[3] < 32 ? '.' : c[3];
434       printf("  move module %02d { %lx, %lx } (%s) -> { %lx - %lx }\n",
435              i, start, end, c, start + offset, end + offset);
436
437       for (int a = 0; a < 0x100; a += 4)
438         printf("%08lx%s", *(unsigned long *)(start + a), (a % 32 == 28) ? "\n" : " ");
439       printf("\n");
440 #else
441       printf("  move module %02d { %lx-%lx } -> { %lx-%lx }\n",
442              i, start, end, start + offset, end + offset);
443 #endif
444
445       Region *overlap = regions.find(Region(start + offset, end + offset));
446       if (overlap)
447         {
448           printf("ERROR: module target [%lx-%lx) overlaps\n", start + offset, 
449               end + offset);
450           overlap->vprint();
451           panic("can not move module");
452         }
453       if (!ram.contains(Region(start + offset, end + offset)))
454         panic("Panic: Would move outside of RAM");
455       memmove((void *)(start+offset), (void *)start, end-start);
456       (L4_MB_MOD_PTR(mbi->mods_addr))[i-1].mod_start += offset;
457       (L4_MB_MOD_PTR(mbi->mods_addr))[i-1].mod_end += offset;
458     }
459 }
460
461
462 /**
463  * Add the bootstrap binary itself to the allocated memory regions.
464  */
465 static void
466 init_regions()
467 {
468   extern int _start;    /* begin of image -- defined in crt0.S */
469   extern int _end;      /* end   of image -- defined by bootstrap.ld */
470
471   regions.add(Region::n((unsigned long)&_start, (unsigned long)&_end,
472               ".bootstrap", Region::Boot));
473 }
474
475
476 /**
477  * Add the memory containing the boot modules to the allocated regions.
478  */
479 static void
480 add_boot_modules_region(l4util_mb_info_t *mbi)
481 {
482   regions.add(
483       Region::n((L4_MB_MOD_PTR(mbi->mods_addr))[0].mod_start,
484              (L4_MB_MOD_PTR(mbi->mods_addr))[mbi->mods_count-1].mod_end,
485              ".Modules Memory", Region::Root));
486 }
487
488
489 /**
490  * Add all sections of the given ELF binary to the allocated regions.
491  * Actually does not load the ELF binary (see load_elf_module()).
492  */
493 static void
494 add_elf_regions(l4util_mb_info_t *mbi, l4_umword_t module,
495                 Region::Type type)
496 {
497   exec_task_t exec_task;
498   l4_addr_t entry;
499   int r;
500   const char *error_msg;
501   l4util_mb_mod_t *mb_mod = (l4util_mb_mod_t*)mbi->mods_addr;
502
503   assert(module < mbi->mods_count);
504
505   exec_task.begin = 0xffffffff;
506   exec_task.end   = 0;
507   exec_task.type = type;
508
509   exec_task.mod_start = L4_VOID_PTR(mb_mod[module].mod_start);
510   exec_task.mod       = mb_mod + module;
511
512   printf("  Scanning %s\n", L4_CHAR_PTR(mb_mod[module].cmdline));
513
514   r = exec_load_elf(l4_exec_add_region, &exec_task,
515                     &error_msg, &entry);
516
517   if (r)
518     {
519 #ifdef VERBOSE_LOAD
520       int i;
521       printf("\n%p: ", exec_task.mod_start);
522       for (i = 0; i < 16; ++i)
523         {
524           printf("%02x", *(unsigned char *)exec_task.mod_start);
525           if (i % 4 == 3)
526             printf(" ");
527         }
528       printf("  ");
529       for (i = 0; i < 16; ++i)
530         {
531           unsigned char c = *(unsigned char *)exec_task.mod_start;
532           printf("%c", c < 32 ? '.' : c);
533         }
534 #endif
535       panic("\n\nThis is an invalid binary, fix it.");
536     }
537 }
538
539
540 /**
541  * Load the given ELF binary into memory and free the source
542  * memory region.
543  */
544 static l4_addr_t
545 load_elf_module(l4util_mb_mod_t *mb_mod)
546 {
547   exec_task_t exec_task;
548   l4_addr_t entry;
549   int r;
550   const char *error_msg;
551
552   exec_task.begin = 0xffffffff;
553   exec_task.end   = 0;
554
555   exec_task.mod_start = L4_VOID_PTR(mb_mod->mod_start);
556   exec_task.mod       = mb_mod;
557
558   r = exec_load_elf(l4_exec_read_exec, &exec_task,
559                     &error_msg, &entry);
560
561 #ifndef RELEASE_MODE
562   /* clear the image for debugging and security reasons */
563   memset(L4_VOID_PTR(mb_mod->mod_start), 0,
564          mb_mod->mod_end - mb_mod->mod_start);
565 #endif
566
567   if (r)
568     printf("  => can't load module (%s)\n", error_msg);
569   else
570     {
571       Region m = Region::n(mb_mod->mod_start, mb_mod->mod_end);
572       Region *x = regions.find(m);
573       if (x)
574         {
575           if (x->begin() == m.begin())
576             {
577               unsigned long b = l4_round_page(m.end()+1);
578               if (x->end() <= b)
579                 regions.remove(x);
580               else
581                 x->begin(b);
582             }
583         }
584     }
585
586   return entry;
587 }
588
589 /**
590  * Simple linear memory allocator.
591  *
592  * Allocate size bytes startting from *ptr and set *ptr to *ptr + size.
593  */
594 static inline void*
595 lin_alloc(l4_size_t size, char **ptr)
596 {
597   void *ret = *ptr;
598   *ptr += (size + 3) & ~3;;
599   return ret;
600 }
601
602
603 /**
604  * Duplicate the given command line.
605  *
606  * This function is use for relocating the multi-boot info.
607  * The new location is *ptr and *ptr is incemented by the size of the
608  * string (basically like lin_alloc() does).
609  *
610  * This function also implements the mechanism to replace the command line
611  * of a module from the bootstrap comand line.
612  */
613 static
614 char *dup_cmdline(l4util_mb_info_t *mbi, unsigned mod_nr, char **ptr,
615     char const *orig)
616 {
617   char *res = *ptr;
618   if (!orig)
619     return 0;
620
621   char* name_end = strchr(orig, ' ');
622   if (name_end && *name_end)
623     *name_end = 0;
624   else
625     name_end = 0;
626
627   unsigned size;
628   char const *new_args = get_arg_module(mbi, orig, &size);
629
630   if (new_args && size)
631     printf("    new args for %d = \"%.*s\"\n", mod_nr, size, new_args);
632   else
633     if (name_end)
634       *name_end = ' ';
635
636   strcpy(*ptr, orig);
637   *ptr+= strlen(*ptr)+1;
638
639   if (new_args)
640     {
641       *((*ptr)-1) = ' ';
642       strncpy(*ptr, new_args, size);
643       *ptr += size;
644       *((*ptr)++) = 0;
645     }
646   return res;
647 }
648
649
650 static
651 void
652 print_e820_map(l4util_mb_info_t *mbi)
653 {
654 #ifndef ARCH_arm
655   printf("  Bootloader MMAP%s\n", mbi->flags & L4UTIL_MB_MEM_MAP
656                                    ? ":" : " not available.");
657 #endif
658
659   if (mbi->flags & L4UTIL_MB_MEM_MAP)
660     {
661       l4util_mb_addr_range_t *mmap;
662       l4util_mb_for_each_mmap_entry(mmap, mbi)
663         {
664           const char *types[] = { "unknown", "RAM", "reserved", "ACPI",
665                                   "ACPI NVS", "unusable" };
666           const char *type_str = (mmap->type < (sizeof(types) / sizeof(types[0])))
667                                  ? types[mmap->type] : types[0];
668
669           printf("    [%9llx, %9llx) %s (%d)\n",
670                  (unsigned long long) mmap->addr,
671                  (unsigned long long) mmap->addr + (unsigned long long) mmap->size,
672                  type_str, (unsigned) mmap->type);
673         }
674     }
675 }
676
677 /**
678  * Relocate and compact the multi-boot infomation (MBI).
679  *
680  * This function relocates the MBI into the first 4MB of physical memory.
681  * Substructures such as module information, the VESA information, and
682  * the command lines of the modules are also relocated.
683  * During relocation of command lines they may be substituted according
684  * to '-arg=' options from the bootstrap command line.
685  *
686  * The memory map is discared and not relocated, because everything after 
687  * bootstrap has to use the KIP memory desriptors.
688  */
689 static
690 l4util_mb_info_t *
691 relocate_mbi(l4util_mb_info_t *src_mbi, unsigned long* start,
692              unsigned long* end)
693 {
694   l4util_mb_info_t *dst_mbi;
695   l4_addr_t x;
696
697   print_e820_map(src_mbi);
698
699   static char mbi_store[16 << 10] __attribute__((aligned(L4_PAGESIZE)));
700
701   x = (l4_addr_t)&mbi_store;
702
703   void *mbi_start = (void*)x;
704
705   char *p = (char*)x;
706   *start = x;
707
708   dst_mbi = (l4util_mb_info_t*)lin_alloc(sizeof(l4util_mb_info_t), &p);
709
710   /* copy (extended) multiboot info structure */
711   memcpy(dst_mbi, src_mbi, sizeof(l4util_mb_info_t));
712
713   dst_mbi->flags &= ~(L4UTIL_MB_CMDLINE | L4UTIL_MB_MEM_MAP | L4UTIL_MB_MEMORY);
714
715   /* copy extended VIDEO information, if available */
716   if (dst_mbi->flags & L4UTIL_MB_VIDEO_INFO)
717     {
718       if (src_mbi->vbe_mode_info)
719         {
720           l4util_mb_vbe_mode_t *m
721             = (l4util_mb_vbe_mode_t*)lin_alloc(sizeof(l4util_mb_vbe_mode_t),
722                 &p);
723
724           memcpy(m, L4_VOID_PTR(src_mbi->vbe_mode_info),
725                  sizeof(l4util_mb_vbe_mode_t));
726           dst_mbi->vbe_mode_info = (l4_addr_t)m;
727         }
728
729       /* copy VBE controller info structure */
730       if (src_mbi->vbe_ctrl_info)
731         {
732           l4util_mb_vbe_ctrl_t *m
733             = (l4util_mb_vbe_ctrl_t*)lin_alloc(sizeof(l4util_mb_vbe_ctrl_t),
734                 &p);
735           memcpy(m, L4_VOID_PTR(src_mbi->vbe_ctrl_info),
736                  sizeof(l4util_mb_vbe_ctrl_t));
737           dst_mbi->vbe_ctrl_info = (l4_addr_t)m;
738         }
739     }
740
741   /* copy module descriptions */
742   l4util_mb_mod_t *mods = (l4util_mb_mod_t*)lin_alloc(sizeof(l4util_mb_mod_t)*
743       src_mbi->mods_count, &p);
744   memcpy(mods, L4_VOID_PTR(dst_mbi->mods_addr),
745          dst_mbi->mods_count * sizeof (l4util_mb_mod_t));
746   dst_mbi->mods_addr = (l4_addr_t)mods;
747
748   /* copy command lines of modules */
749   for (unsigned i = 0; i < dst_mbi->mods_count; i++)
750     {
751       char *n = dup_cmdline(src_mbi, i, &p, (char const *)(mods[i].cmdline));
752       if (n)
753           mods[i].cmdline = (l4_addr_t) n;
754     }
755   *end = (l4_addr_t)p;
756
757   printf("  Relocated mbi to [%p-%p]\n", mbi_start, (void*)(*end));
758   regions.add(Region::n((unsigned long)mbi_start,
759                         ((unsigned long)*end) + 0xfe,
760                         ".Multiboot info", Region::Root),
761               true /* we overlap with the Bootstrap binary, we are in BSS*/);
762
763   return dst_mbi;
764 }
765
766 #ifdef IMAGE_MODE
767
768 #ifdef COMPRESS
769 #include "uncompress.h"
770 #endif
771
772 //#define DO_CHECK_MD5
773 #ifdef DO_CHECK_MD5
774 #include <bsd/md5.h>
775
776 static void check_md5(const char *name, u_int8_t *start, unsigned size,
777                       const char *md5sum)
778 {
779   MD5_CTX md5ctx;
780   unsigned char digest[MD5_DIGEST_LENGTH];
781   char s[MD5_DIGEST_STRING_LENGTH];
782   static const char hex[] = "0123456789abcdef";
783   int j;
784
785   printf(" Checking checksum of %s\n", name);
786
787   MD5Init(&md5ctx);
788   MD5Update(&md5ctx, start, size);
789   MD5Final(digest, &md5ctx);
790
791   for (j = 0; j < MD5_DIGEST_LENGTH; j++)
792     {
793       s[j + j] = hex[digest[j] >> 4];
794       s[j + j + 1] = hex[digest[j] & 0x0f];
795     }
796   s[j + j] = '\0';
797
798   if (strcmp(s, md5sum))
799     panic("md5sum mismatch");
800 }
801 #else
802 static inline void check_md5(const char *, u_int8_t *, unsigned, const char *)
803 {}
804 #endif
805
806 typedef struct
807 {
808   l4_uint32_t  start;
809   l4_uint32_t  size;
810   l4_uint32_t  size_uncompressed;
811   l4_uint32_t  name;
812   l4_uint32_t  md5sum_compr;
813   l4_uint32_t  md5sum_uncompr;
814 } mod_info;
815
816 extern mod_info _module_info_start[];
817 extern mod_info _module_info_end[];
818
819 extern l4util_mb_mod_t _modules_mbi_start[];
820 extern l4util_mb_mod_t _modules_mbi_end[];
821
822 /**
823  * Create the basic multi-boot structure in IMAGE_MODE
824  */
825 static void
826 construct_mbi(l4util_mb_info_t *mbi)
827 {
828   unsigned i;
829   l4util_mb_mod_t *mods = _modules_mbi_start;
830 #ifdef COMPRESS
831   l4_addr_t destbuf;
832 #endif
833
834   mbi->mods_count  = _module_info_end - _module_info_start;
835   mbi->flags      |= L4UTIL_MB_MODS;
836   mbi->mods_addr   = (l4_addr_t)mods;
837
838   assert(mbi->mods_count >= 2);
839
840   for (i = 0; i < mbi->mods_count; ++i)
841     check_md5(L4_CHAR_PTR(_module_info_start[i].name),
842               (u_int8_t *)_module_info_start[i].start,
843               _module_info_start[i].size,
844               L4_CHAR_PTR(_module_info_start[i].md5sum_compr));
845
846 #ifdef COMPRESS
847   printf("Compressed modules:\n");
848   for (i = 0; i < mbi->mods_count; i++)
849     {
850       printf("  mod%02u: %08x-%08x: %s\n",
851              i, _module_info_start[i].start,
852              _module_info_start[i].start + _module_info_start[i].size,
853              L4_CHAR_PTR(_module_info_start[i].name));
854     }
855
856   destbuf = l4_round_page(mods[mbi->mods_count - 1].mod_end);
857   if (destbuf < _mod_addr)
858     destbuf = _mod_addr;
859
860   // advance to last module end
861   for (i = 0; i < mbi->mods_count; i++)
862     destbuf += l4_round_page(_module_info_start[i].size_uncompressed);
863
864   // check for overlaps and adjust mod_addr accordingly
865   unsigned long d = destbuf;
866   for (i = mbi->mods_count; i > 0; --i)
867     {
868       d -= l4_round_page(_module_info_start[i - 1].size_uncompressed);
869       if (d <= _module_info_start[i-1].start + _module_info_start[i-1].size)
870         {
871           l4_addr_t x = (_module_info_start[i-1].start + _module_info_start[i-1].size + 0xfff) & ~0xfff;
872           l4_addr_t delta = x - d;
873
874           _mod_addr += delta;
875           destbuf += delta;
876           printf("  Adjusting modaddr to %lx {%d}\n", _mod_addr, i-1);
877           d = x;
878         }
879     }
880
881   printf("Uncompressing modules (modaddr = %lx):\n", _mod_addr);
882 #endif
883
884   for (i = mbi->mods_count; i > 0; --i)
885     {
886 #ifdef COMPRESS
887       destbuf -= l4_round_page(_module_info_start[i - 1].size_uncompressed);
888
889       l4_addr_t image =
890          (l4_addr_t)decompress(L4_CONST_CHAR_PTR(_module_info_start[i - 1].name),
891                                L4_VOID_PTR(_module_info_start[i - 1].start),
892                                (void *)destbuf,
893                                _module_info_start[i - 1].size,
894                                _module_info_start[i - 1].size_uncompressed);
895 #else
896       l4_addr_t image = _module_info_start[i - 1].start;
897 #endif
898       mods[i - 1].mod_start = image;
899       mods[i - 1].mod_end   = image + _module_info_start[i - 1].size_uncompressed;
900       printf("  mod%02u: %08x-%08x: %s\n",
901              i - 1, mods[i - 1].mod_start, mods[i - 1].mod_end,
902              L4_CHAR_PTR(_module_info_start[i - 1].name));
903       if (image == 0)
904         panic("Panic: Failure decompressing image\n");
905       if (!ram.contains(Region(mods[i - 1].mod_start,
906                                mods[i - 1].mod_end)))
907         panic("Panic: Module does not fit into RAM");
908
909     }
910
911   for (i = 0; i < mbi->mods_count; ++i)
912     check_md5(L4_CHAR_PTR(_module_info_start[i].name),
913               (u_int8_t *)mods[i].mod_start,
914               _module_info_start[i].size_uncompressed,
915               L4_CHAR_PTR(_module_info_start[i].md5sum_uncompr));
916 }
917 #endif /* IMAGE_MODE */
918
919
920 void
921 init_pc_serial(l4util_mb_info_t *mbi)
922 {
923 #if defined(ARCH_x86) || defined(ARCH_amd64)
924   const char *s;
925   int comport = -1;
926
927   if ((s = check_arg(mbi, "-comport")))
928     comport = strtoul(s + 9, 0, 0);
929
930   if (check_arg(mbi, "-serial"))
931     {
932       if (0)
933         {
934           extern unsigned long search_pci_serial_devs(bool scan_only);
935           unsigned long port;
936           if (comport == -1
937               && (port = search_pci_serial_devs(false)))
938             comport = port;
939         }
940
941       if (comport == -1)
942         comport = 1;
943
944       com_cons_init(comport);
945     }
946 #else
947   (void)mbi;
948 #endif
949
950 }
951
952 #ifdef ARCH_arm
953 #ifndef IMAGE_MODE
954 // check that our is_precious_ram function can work ok
955 #error For ARM, IMAGE_MODE must always be enabled
956 #endif
957
958 /* Occupied RAM at the point we are scannig it */
959 static int
960 is_precious_ram(unsigned long addr)
961 {
962   extern int _start, _end;
963   unsigned i, c = _module_info_end - _module_info_start;
964
965   if ((unsigned long)&_start <= addr && addr <= (unsigned long)&_end)
966     return 1;
967
968   if ((unsigned long)_module_info_start <= addr
969        && addr <= (unsigned long)_module_info_end)
970     return 1;
971
972   if ((unsigned long)_modules_mbi_start <= addr
973       && addr <= (unsigned long)_modules_mbi_end)
974     return 1;
975
976   for (i = 0; i < c; ++i)
977     if (_module_info_start[i].start <= addr
978         && _module_info_start[i].start + _module_info_start[i].size_uncompressed <= addr)
979       return 1;
980
981   return 0;
982 }
983
984 unsigned long
985 scan_ram_size(unsigned long base_addr, unsigned long max_scan_size_mb)
986 {
987   // scan the RAM to find out the RAM size, note that at this point we have
988   // two regions in RAM that we cannot touch, &_start - &_end and the
989   // modules
990
991   unsigned long offset;
992   const unsigned long increment = 1 << 20; // must be multiple of (1 << 20)
993
994   printf("  Scanning up to %ld MB RAM\n", max_scan_size_mb);
995
996   // initialize memory points
997   for (offset = increment; offset < (max_scan_size_mb << 20); offset += offset)
998     if (!is_precious_ram(base_addr + offset))
999       *(unsigned long *)(base_addr + offset) = 0;
1000
1001   // write something at offset 0, does it appear elsewhere?
1002   *(unsigned long *)base_addr = 0x12345678;
1003   asm volatile("" : : : "memory");
1004   for (offset = increment; offset < (max_scan_size_mb << 20); offset += offset)
1005     if (*(unsigned long *)(base_addr + offset) == 0x12345678)
1006       return offset >> 20;
1007
1008   return max_scan_size_mb;
1009 }
1010 #endif
1011
1012 /**
1013  * \brief  Startup, started from crt0.S
1014  */
1015 /* entry point */
1016 extern "C" void
1017 startup(l4util_mb_info_t *mbi, l4_umword_t flag,
1018         void *realmode_si, ptab64_mem_info_t *ptab64_info);
1019 void
1020 startup(l4util_mb_info_t *mbi, l4_umword_t flag,
1021         void *realmode_si, ptab64_mem_info_t *ptab64_info)
1022 {
1023   void *l4i;
1024   boot_info_t boot_info;
1025   l4util_mb_mod_t *mb_mod;
1026
1027   /* fire up serial port if specificed on the command line */
1028   init_pc_serial(mbi);
1029
1030   if (!Platform_base::platform)
1031     {
1032       // will we ever see this?
1033       printf("No platform found, hangup.");
1034       while (1)
1035         ;
1036     }
1037
1038   puts("\nL4 Bootstrapper");
1039   puts("  Build: #" BUILD_NR " " BUILD_DATE);
1040
1041   regions.init(__regs, sizeof(__regs)/sizeof(__regs[0]), "regions");
1042   ram.init(__ram, sizeof(__ram)/sizeof(__ram[0]), "RAM",
1043            get_memory_limit(mbi));
1044
1045 #ifdef ARCH_amd64
1046   // add the page-table on which we're running in 64bit mode
1047   regions.add(Region::n(ptab64_info->addr, ptab64_info->addr + ptab64_info->size,
1048               ".bootstrap-ptab64", Region::Boot));
1049 #else
1050   (void)ptab64_info;
1051 #endif
1052
1053 #if defined(ARCH_x86) || defined(ARCH_amd64)
1054
1055 #ifdef REALMODE_LOADING
1056   /* create synthetic multi boot info */
1057   mbi = init_loader_mbi(realmode_si);
1058 #else
1059   (void)realmode_si;
1060   assert(flag == L4UTIL_MB_VALID); /* we need to be multiboot-booted */
1061 #endif
1062
1063 #elif defined(ARCH_arm)
1064   l4util_mb_info_t my_mbi;
1065   memset(&my_mbi, 0, sizeof(my_mbi));
1066   mbi = &my_mbi;
1067
1068   (void)realmode_si;
1069   (void)flag;
1070
1071 #elif defined(ARCH_ppc32)
1072   (void)realmode_si;
1073   (void)flag;
1074
1075   l4util_mb_info_t my_mbi;
1076   L4_drivers::Of_if of_if;
1077
1078   printf("  Detecting ram size ...\n");
1079   unsigned long ram_size = of_if.detect_ramsize();
1080   printf("    Total memory size is %luMB\n", ram_size / (1024 * 1024));
1081
1082   /* setup mbi and detect OF devices */
1083   memset(&my_mbi, 0, sizeof(my_mbi));
1084   mbi = &my_mbi;
1085   unsigned long drives_addr, drives_length;
1086
1087   if (of_if.detect_devices(&drives_addr, &drives_length))
1088     {
1089       mbi->flags |= L4UTIL_MB_DRIVE_INFO;
1090       mbi->drives_addr   = drives_addr;
1091       mbi->drives_length = drives_length;
1092     }
1093   ram.add(Region::n(0x0, ram_size, ".ram", Region::Ram));
1094
1095 #else
1096 #error Unknown arch!
1097 #endif
1098
1099   setup_memory_map(mbi);
1100
1101   /* basically add the bootstrap binary to the allocated regions */
1102   init_regions();
1103
1104   /* check command line */
1105   if (check_arg(mbi, "-no-sigma0"))
1106     sigma0 = 0;
1107
1108   if (check_arg(mbi, "-no-roottask"))
1109     roottask = 0;
1110
1111   if (const char *s = check_arg(mbi, "-modaddr"))
1112     _mod_addr = strtoul(s + 9, 0, 0);
1113
1114 #ifdef IMAGE_MODE
1115   construct_mbi(mbi);
1116 #endif
1117
1118   /* move vbe and ctrl structures to a known location, it might be in the
1119    * way when moving modules around */
1120 #if defined(ARCH_x86) || defined(ARCH_amd64)
1121   if (mbi->flags & L4UTIL_MB_VIDEO_INFO)
1122     {
1123       if (mbi->vbe_mode_info)
1124         {
1125           memcpy(&__mb_vbe, L4_VOID_PTR(mbi->vbe_mode_info),
1126                  sizeof(l4util_mb_vbe_mode_t));
1127           mbi->vbe_mode_info = (l4_addr_t)&__mb_vbe;
1128         }
1129
1130       if (mbi->vbe_ctrl_info)
1131         {
1132           memcpy(&__mb_ctrl, L4_VOID_PTR(mbi->vbe_ctrl_info),
1133                  sizeof(l4util_mb_vbe_ctrl_t));
1134           mbi->vbe_ctrl_info = (l4_addr_t)&__mb_ctrl;
1135         }
1136     }
1137 #endif
1138
1139   if (_mod_addr)
1140     move_modules(mbi, _mod_addr);
1141
1142   /* We need at least two boot modules */
1143   assert(mbi->flags & L4UTIL_MB_MODS);
1144   /* We have at least the L4 kernel and the first user task */
1145   assert(mbi->mods_count >= 2);
1146   assert(mbi->mods_count <= MODS_MAX);
1147
1148   /* we're just a GRUB-booted kernel! */
1149   add_boot_modules_region(mbi);
1150
1151   if (const char *s = get_cmdline(mbi))
1152     {
1153       /* patch modules with content given at command line */
1154       while ((s = check_arg_str((char *)s, "-patch=")))
1155         patch_module(&s, mbi);
1156     }
1157
1158
1159   add_elf_regions(mbi, kernel_module, Region::Kernel);
1160
1161   if (sigma0)
1162     add_elf_regions(mbi, sigma0_module, Region::Sigma0);
1163
1164   if (roottask)
1165     add_elf_regions(mbi, roottask_module, Region::Root);
1166
1167
1168   /* copy Multiboot data structures, we still need to a safe place
1169    * before playing with memory we don't own and starting L4 */
1170   mb_info = relocate_mbi(mbi, &boot_info.mbi_low, &boot_info.mbi_high);
1171   if (!mb_info)
1172     panic("could not copy multiboot info to memory below 4MB");
1173
1174   mb_mod = (l4util_mb_mod_t*)mb_info->mods_addr;
1175
1176   /* --- Shouldn't touch original Multiboot parameters after here. -- */
1177
1178   /* setup kernel PART ONE */
1179   printf("  Loading ");
1180   print_module_name(L4_CONST_CHAR_PTR(mb_mod[kernel_module].cmdline),
1181       "[KERNEL]");
1182   putchar('\n');
1183
1184   boot_info.kernel_start = load_elf_module(mb_mod + kernel_module);
1185
1186   /* setup sigma0 */
1187   if (sigma0)
1188     {
1189       printf("  Loading ");
1190       print_module_name(L4_CONST_CHAR_PTR(mb_mod[sigma0_module].cmdline),
1191                          "[SIGMA0]");
1192       putchar('\n');
1193
1194       boot_info.sigma0_start = load_elf_module(mb_mod + sigma0_module);
1195       boot_info.sigma0_stack = (l4_addr_t)sigma0_init_stack
1196                                + sizeof(sigma0_init_stack);
1197     }
1198
1199   /* setup roottask */
1200   if (roottask)
1201     {
1202
1203       printf("  Loading ");
1204       print_module_name(L4_CONST_CHAR_PTR(mb_mod[roottask_module].cmdline),
1205                          "[ROOTTASK]");
1206       putchar('\n');
1207
1208       boot_info.roottask_start = load_elf_module(mb_mod + roottask_module);
1209       boot_info.roottask_stack = (l4_addr_t)roottask_init_stack
1210                                  + sizeof(roottask_init_stack);
1211     }
1212
1213   /* setup kernel PART TWO (special kernel initialization) */
1214   l4i = find_kip();
1215
1216 #if defined(ARCH_x86) || defined(ARCH_amd64) || defined(ARCH_ppc32)
1217   /* setup multi boot info structure for kernel */
1218   l4util_mb_info_t kernel_mbi;
1219   kernel_mbi = *mb_info;
1220   kernel_mbi.flags = L4UTIL_MB_MEMORY;
1221   if (mb_mod[kernel_module].cmdline)
1222     {
1223       kernel_mbi.cmdline = mb_mod[kernel_module].cmdline;
1224       kernel_mbi.flags  |= L4UTIL_MB_CMDLINE;
1225     }
1226 #endif
1227
1228   regions.optimize();
1229   regions.dump();
1230
1231   if (char *c = check_arg(mbi, "-presetmem="))
1232     {
1233       unsigned fill_value = strtoul(c + 11, NULL, 0);
1234       fill_mem(fill_value);
1235     }
1236
1237   /* setup the L4 kernel info page before booting the L4 microkernel:
1238    * patch ourselves into the booter task addresses */
1239   unsigned long api_version = get_api_version(l4i);
1240   unsigned major = api_version >> 24;
1241   printf("  API Version: (%x) %s\n", major, (major & 0x80)?"experimental":"");
1242   switch (major)
1243     {
1244     case 0x02: // Version 2 API
1245     case 0x03: // Version X.0 and X.1
1246     case 0x87: // Fiasco
1247       init_kip_v2(l4i, &boot_info, mb_info, &ram, &regions);
1248       //init_kip_kuart_info(l4i, &kip_kernel_uart_info);
1249       break;
1250     case 0x84:
1251     case 0x04:
1252       init_kip_v4(l4i, &boot_info, mb_info, &ram, &regions);
1253       break;
1254     default:
1255       panic("cannot boot a kernel with unknown api version %lx\n", api_version);
1256       break;
1257     }
1258
1259   printf("  Starting kernel ");
1260   print_module_name(L4_CONST_CHAR_PTR(mb_mod[kernel_module].cmdline),
1261                     "[KERNEL]");
1262   printf(" at "l4_addr_fmt"\n", boot_info.kernel_start);
1263
1264 #if defined(ARCH_x86)
1265   asm volatile
1266     ("pushl $exit ; jmp *%3"
1267      :
1268      : "a" (L4UTIL_MB_VALID),
1269        "b" (&kernel_mbi),
1270        "S" (realmode_si),
1271        "r" (boot_info.kernel_start));
1272
1273 #elif defined(ARCH_amd64)
1274
1275   asm volatile
1276     ("push $exit; jmp *%2"
1277      :
1278      : "S" (L4UTIL_MB_VALID), "D" (&kernel_mbi), "r" (boot_info.kernel_start));
1279
1280 #elif defined(ARCH_arm)
1281   typedef void (*startup_func)(void);
1282   startup_func f = (startup_func)boot_info.kernel_start;
1283   f();
1284
1285 #elif defined(ARCH_ppc32)
1286
1287   init_kip_v2_arch((l4_kernel_info_t*)l4i);
1288   printf("CPU at %lu Khz/Bus at %lu Hz\n",
1289          ((l4_kernel_info_t*)l4i)->frequency_cpu,
1290          ((l4_kernel_info_t*)l4i)->frequency_bus);
1291   typedef void (*startup_func)(l4util_mb_info_t *, unsigned long);
1292   startup_func f = (startup_func)boot_info.kernel_start;
1293   of_if.boot_finish();
1294   f(&kernel_mbi, of_if.get_prom());
1295 #else
1296
1297 #error "How to enter the kernel?"
1298
1299 #endif
1300
1301   /*NORETURN*/
1302 }
1303
1304 static int
1305 l4_exec_read_exec(void * handle,
1306                   l4_addr_t file_ofs, l4_size_t file_size,
1307                   l4_addr_t mem_addr, l4_addr_t /*v_addr*/,
1308                   l4_size_t mem_size,
1309                   exec_sectype_t section_type)
1310 {
1311   exec_task_t *exec_task = (exec_task_t*)handle;
1312   if (!mem_size)
1313     return 0;
1314
1315   if (! (section_type & EXEC_SECTYPE_ALLOC))
1316     return 0;
1317
1318   if (! (section_type & (EXEC_SECTYPE_ALLOC|EXEC_SECTYPE_LOAD)))
1319     return 0;
1320
1321   if (mem_addr < exec_task->begin)
1322     exec_task->begin = mem_addr;
1323   if (mem_addr + mem_size > exec_task->end)
1324     exec_task->end = mem_addr + mem_size;
1325
1326 #ifdef VERBOSE_LOAD
1327   printf("    [%p-%p]\n", (void *) mem_addr, (void *) (mem_addr + mem_size));
1328 #endif
1329
1330   if (!ram.contains(Region::n(mem_addr, mem_addr + mem_size)))
1331     {
1332       printf("To be loaded binary region is out of memory region.\n");
1333       printf(" Binary region: %lx - %lx\n", mem_addr, mem_addr + mem_size);
1334       dump_ram_map();
1335       panic("Binary outside memory");
1336     }
1337
1338   memcpy((void *) mem_addr,
1339          (char*)(exec_task->mod_start) + file_ofs, file_size);
1340   if (file_size < mem_size)
1341     memset((void *) (mem_addr + file_size), 0, mem_size - file_size);
1342
1343
1344   Region *f = regions.find(mem_addr);
1345   if (!f)
1346     {
1347       printf("could not find %lx\n", mem_addr);
1348       regions.dump();
1349       panic("Oops: region for module not found\n");
1350     }
1351
1352   f->name(exec_task->mod->cmdline
1353                ? L4_CONST_CHAR_PTR(exec_task->mod->cmdline)
1354                :  ".[Unknown]");
1355   return 0;
1356 }
1357
1358 static int
1359 l4_exec_add_region(void * handle,
1360                   l4_addr_t /*file_ofs*/, l4_size_t /*file_size*/,
1361                   l4_addr_t mem_addr, l4_addr_t v_addr,
1362                   l4_size_t mem_size,
1363                   exec_sectype_t section_type)
1364 {
1365   exec_task_t *exec_task = (exec_task_t*)handle;
1366
1367   if (!mem_size)
1368     return 0;
1369
1370   if (! (section_type & EXEC_SECTYPE_ALLOC))
1371     return 0;
1372
1373   if (! (section_type & (EXEC_SECTYPE_ALLOC|EXEC_SECTYPE_LOAD)))
1374     return 0;
1375
1376   regions.add(Region::n(mem_addr, mem_addr + mem_size,
1377              exec_task->mod->cmdline
1378                ? L4_CONST_CHAR_PTR(exec_task->mod->cmdline)
1379                :  ".[Unknown]", Region::Type(exec_task->type),
1380                mem_addr == v_addr ? 1 : 0));
1381   return 0;
1382 }