]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/bootstrap/server/src/startup.cc
99505a0519ea8b4e8cc9897261164701f63e4047
[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, i_end;
405   unsigned dir = offset > 0 ? -1 : 1;
406
407   if (!offset)
408     {
409       printf("  => Images in place\n");
410       return;
411     }
412
413   printf("  Moving %d modules to %lx with offset %lx\n",
414          mbi->mods_count, modaddr, offset);
415
416   i     = dir == 1 ? 1 : mbi->mods_count;
417   i_end = dir == 1 ? mbi->mods_count + 1 : 0;
418   for (; i != i_end ; i += dir)
419     {
420       unsigned long start = (L4_MB_MOD_PTR(mbi->mods_addr))[i-1].mod_start;
421       unsigned long end = (L4_MB_MOD_PTR(mbi->mods_addr))[i-1].mod_end;
422
423       if (start == end)
424         continue;
425
426 #ifdef VERBOSE_LOAD
427       unsigned char c[5];
428       c[0] = *(unsigned char*)(start + 0);
429       c[1] = *(unsigned char*)(start + 1);
430       c[2] = *(unsigned char*)(start + 2);
431       c[3] = *(unsigned char*)(start + 3);
432       c[4] = 0;
433       c[0] = c[0] < 32 ? '.' : c[0];
434       c[1] = c[1] < 32 ? '.' : c[1];
435       c[2] = c[2] < 32 ? '.' : c[2];
436       c[3] = c[3] < 32 ? '.' : c[3];
437       printf("  moving module %02d { %lx, %lx } (%s) -> { %lx - %lx }\n",
438              i, start, end, c, start + offset, end + offset);
439
440       for (int a = 0; a < 0x100; a += 4)
441         printf("%08lx%s", *(unsigned long *)(start + a), (a % 32 == 28) ? "\n" : " ");
442       printf("\n");
443 #else
444       printf("  moving module %02d { %lx-%lx } -> { %lx-%lx }\n",
445              i, start, end, start + offset, end + offset);
446 #endif
447
448       Region *overlap = regions.find(Region(start + offset, end + offset));
449       if (overlap)
450         {
451           printf("ERROR: module target [%lx-%lx) overlaps\n", start + offset, 
452               end + offset);
453           overlap->vprint();
454           panic("can not move module");
455         }
456       if (!ram.contains(Region(start + offset, end + offset)))
457         panic("Panic: Would move outside of RAM");
458       memmove((void *)(start+offset), (void *)start, end-start);
459       (L4_MB_MOD_PTR(mbi->mods_addr))[i-1].mod_start += offset;
460       (L4_MB_MOD_PTR(mbi->mods_addr))[i-1].mod_end += offset;
461     }
462 }
463
464
465 /**
466  * Add the bootstrap binary itself to the allocated memory regions.
467  */
468 static void
469 init_regions()
470 {
471   extern int _start;    /* begin of image -- defined in crt0.S */
472   extern int _end;      /* end   of image -- defined by bootstrap.ld */
473
474   regions.add(Region::n((unsigned long)&_start, (unsigned long)&_end,
475               ".bootstrap", Region::Boot));
476 }
477
478
479 /**
480  * Add the memory containing the boot modules to the allocated regions.
481  */
482 static void
483 add_boot_modules_region(l4util_mb_info_t *mbi)
484 {
485   regions.add(
486       Region::n((L4_MB_MOD_PTR(mbi->mods_addr))[0].mod_start,
487              (L4_MB_MOD_PTR(mbi->mods_addr))[mbi->mods_count-1].mod_end,
488              ".Modules Memory", Region::Root));
489 }
490
491
492 /**
493  * Add all sections of the given ELF binary to the allocated regions.
494  * Actually does not load the ELF binary (see load_elf_module()).
495  */
496 static void
497 add_elf_regions(l4util_mb_info_t *mbi, l4_umword_t module,
498                 Region::Type type)
499 {
500   exec_task_t exec_task;
501   l4_addr_t entry;
502   int r;
503   const char *error_msg;
504   l4util_mb_mod_t *mb_mod = (l4util_mb_mod_t*)mbi->mods_addr;
505
506   assert(module < mbi->mods_count);
507
508   exec_task.begin = 0xffffffff;
509   exec_task.end   = 0;
510   exec_task.type = type;
511
512   exec_task.mod_start = L4_VOID_PTR(mb_mod[module].mod_start);
513   exec_task.mod       = mb_mod + module;
514
515   printf("  Scanning %s\n", L4_CHAR_PTR(mb_mod[module].cmdline));
516
517   r = exec_load_elf(l4_exec_add_region, &exec_task,
518                     &error_msg, &entry);
519
520   if (r)
521     {
522 #ifdef VERBOSE_LOAD
523       int i;
524       printf("\n%p: ", exec_task.mod_start);
525       for (i = 0; i < 16; ++i)
526         {
527           printf("%02x", *(unsigned char *)exec_task.mod_start);
528           if (i % 4 == 3)
529             printf(" ");
530         }
531       printf("  ");
532       for (i = 0; i < 16; ++i)
533         {
534           unsigned char c = *(unsigned char *)exec_task.mod_start;
535           printf("%c", c < 32 ? '.' : c);
536         }
537 #endif
538       panic("\n\nThis is an invalid binary, fix it.");
539     }
540 }
541
542
543 /**
544  * Load the given ELF binary into memory and free the source
545  * memory region.
546  */
547 static l4_addr_t
548 load_elf_module(l4util_mb_mod_t *mb_mod)
549 {
550   exec_task_t exec_task;
551   l4_addr_t entry;
552   int r;
553   const char *error_msg;
554
555   exec_task.begin = 0xffffffff;
556   exec_task.end   = 0;
557
558   exec_task.mod_start = L4_VOID_PTR(mb_mod->mod_start);
559   exec_task.mod       = mb_mod;
560
561   r = exec_load_elf(l4_exec_read_exec, &exec_task,
562                     &error_msg, &entry);
563
564 #ifndef RELEASE_MODE
565   /* clear the image for debugging and security reasons */
566   memset(L4_VOID_PTR(mb_mod->mod_start), 0,
567          mb_mod->mod_end - mb_mod->mod_start);
568 #endif
569
570   if (r)
571     printf("  => can't load module (%s)\n", error_msg);
572   else
573     {
574       Region m = Region::n(mb_mod->mod_start, mb_mod->mod_end);
575       Region *x = regions.find(m);
576       if (x)
577         {
578           if (x->begin() == m.begin())
579             {
580               unsigned long b = l4_round_page(m.end()+1);
581               if (x->end() <= b)
582                 regions.remove(x);
583               else
584                 x->begin(b);
585             }
586         }
587     }
588
589   return entry;
590 }
591
592 /**
593  * Simple linear memory allocator.
594  *
595  * Allocate size bytes startting from *ptr and set *ptr to *ptr + size.
596  */
597 static inline void*
598 lin_alloc(l4_size_t size, char **ptr)
599 {
600   void *ret = *ptr;
601   *ptr += (size + 3) & ~3;;
602   return ret;
603 }
604
605
606 /**
607  * Duplicate the given command line.
608  *
609  * This function is use for relocating the multi-boot info.
610  * The new location is *ptr and *ptr is incemented by the size of the
611  * string (basically like lin_alloc() does).
612  *
613  * This function also implements the mechanism to replace the command line
614  * of a module from the bootstrap comand line.
615  */
616 static
617 char *dup_cmdline(l4util_mb_info_t *mbi, unsigned mod_nr, char **ptr,
618     char const *orig)
619 {
620   char *res = *ptr;
621   if (!orig)
622     return 0;
623
624   char* name_end = strchr(orig, ' ');
625   if (name_end && *name_end)
626     *name_end = 0;
627   else
628     name_end = 0;
629
630   unsigned size;
631   char const *new_args = get_arg_module(mbi, orig, &size);
632
633   if (new_args && size)
634     printf("    new args for %d = \"%.*s\"\n", mod_nr, size, new_args);
635   else
636     if (name_end)
637       *name_end = ' ';
638
639   strcpy(*ptr, orig);
640   *ptr+= strlen(*ptr)+1;
641
642   if (new_args)
643     {
644       *((*ptr)-1) = ' ';
645       strncpy(*ptr, new_args, size);
646       *ptr += size;
647       *((*ptr)++) = 0;
648     }
649   return res;
650 }
651
652
653 static
654 void
655 print_e820_map(l4util_mb_info_t *mbi)
656 {
657 #ifndef ARCH_arm
658   printf("  Bootloader MMAP%s\n", mbi->flags & L4UTIL_MB_MEM_MAP
659                                    ? ":" : " not available.");
660 #endif
661
662   if (mbi->flags & L4UTIL_MB_MEM_MAP)
663     {
664       l4util_mb_addr_range_t *mmap;
665       l4util_mb_for_each_mmap_entry(mmap, mbi)
666         {
667           const char *types[] = { "unknown", "RAM", "reserved", "ACPI",
668                                   "ACPI NVS", "unusable" };
669           const char *type_str = (mmap->type < (sizeof(types) / sizeof(types[0])))
670                                  ? types[mmap->type] : types[0];
671
672           printf("    [%9llx, %9llx) %s (%d)\n",
673                  (unsigned long long) mmap->addr,
674                  (unsigned long long) mmap->addr + (unsigned long long) mmap->size,
675                  type_str, (unsigned) mmap->type);
676         }
677     }
678 }
679
680 /**
681  * Relocate and compact the multi-boot infomation (MBI).
682  *
683  * This function relocates the MBI into the first 4MB of physical memory.
684  * Substructures such as module information, the VESA information, and
685  * the command lines of the modules are also relocated.
686  * During relocation of command lines they may be substituted according
687  * to '-arg=' options from the bootstrap command line.
688  *
689  * The memory map is discared and not relocated, because everything after 
690  * bootstrap has to use the KIP memory desriptors.
691  */
692 static
693 l4util_mb_info_t *
694 relocate_mbi(l4util_mb_info_t *src_mbi, unsigned long* start,
695              unsigned long* end)
696 {
697   l4util_mb_info_t *dst_mbi;
698   l4_addr_t x;
699
700   print_e820_map(src_mbi);
701
702   static char mbi_store[16 << 10] __attribute__((aligned(L4_PAGESIZE)));
703
704   x = (l4_addr_t)&mbi_store;
705
706   void *mbi_start = (void*)x;
707
708   char *p = (char*)x;
709   *start = x;
710
711   dst_mbi = (l4util_mb_info_t*)lin_alloc(sizeof(l4util_mb_info_t), &p);
712
713   /* copy (extended) multiboot info structure */
714   memcpy(dst_mbi, src_mbi, sizeof(l4util_mb_info_t));
715
716   dst_mbi->flags &= ~(L4UTIL_MB_CMDLINE | L4UTIL_MB_MEM_MAP | L4UTIL_MB_MEMORY);
717
718   /* copy extended VIDEO information, if available */
719   if (dst_mbi->flags & L4UTIL_MB_VIDEO_INFO)
720     {
721       if (src_mbi->vbe_mode_info)
722         {
723           l4util_mb_vbe_mode_t *m
724             = (l4util_mb_vbe_mode_t*)lin_alloc(sizeof(l4util_mb_vbe_mode_t),
725                 &p);
726
727           memcpy(m, L4_VOID_PTR(src_mbi->vbe_mode_info),
728                  sizeof(l4util_mb_vbe_mode_t));
729           dst_mbi->vbe_mode_info = (l4_addr_t)m;
730         }
731
732       /* copy VBE controller info structure */
733       if (src_mbi->vbe_ctrl_info)
734         {
735           l4util_mb_vbe_ctrl_t *m
736             = (l4util_mb_vbe_ctrl_t*)lin_alloc(sizeof(l4util_mb_vbe_ctrl_t),
737                 &p);
738           memcpy(m, L4_VOID_PTR(src_mbi->vbe_ctrl_info),
739                  sizeof(l4util_mb_vbe_ctrl_t));
740           dst_mbi->vbe_ctrl_info = (l4_addr_t)m;
741         }
742     }
743
744   /* copy module descriptions */
745   l4util_mb_mod_t *mods = (l4util_mb_mod_t*)lin_alloc(sizeof(l4util_mb_mod_t)*
746       src_mbi->mods_count, &p);
747   memcpy(mods, L4_VOID_PTR(dst_mbi->mods_addr),
748          dst_mbi->mods_count * sizeof (l4util_mb_mod_t));
749   dst_mbi->mods_addr = (l4_addr_t)mods;
750
751   /* copy command lines of modules */
752   for (unsigned i = 0; i < dst_mbi->mods_count; i++)
753     {
754       char *n = dup_cmdline(src_mbi, i, &p, (char const *)(mods[i].cmdline));
755       if (n)
756           mods[i].cmdline = (l4_addr_t) n;
757     }
758   *end = (l4_addr_t)p;
759
760   printf("  Relocated mbi to [%p-%p]\n", mbi_start, (void*)(*end));
761   regions.add(Region::n((unsigned long)mbi_start,
762                         ((unsigned long)*end) + 0xfe,
763                         ".Multiboot info", Region::Root),
764               true /* we overlap with the Bootstrap binary, we are in BSS*/);
765
766   return dst_mbi;
767 }
768
769 #ifdef IMAGE_MODE
770
771 #ifdef COMPRESS
772 #include "uncompress.h"
773 #endif
774
775 //#define DO_CHECK_MD5
776 #ifdef DO_CHECK_MD5
777 #include <bsd/md5.h>
778
779 static void check_md5(const char *name, u_int8_t *start, unsigned size,
780                       const char *md5sum)
781 {
782   MD5_CTX md5ctx;
783   unsigned char digest[MD5_DIGEST_LENGTH];
784   char s[MD5_DIGEST_STRING_LENGTH];
785   static const char hex[] = "0123456789abcdef";
786   int j;
787
788   printf(" Checking checksum of %s\n", name);
789
790   MD5Init(&md5ctx);
791   MD5Update(&md5ctx, start, size);
792   MD5Final(digest, &md5ctx);
793
794   for (j = 0; j < MD5_DIGEST_LENGTH; j++)
795     {
796       s[j + j] = hex[digest[j] >> 4];
797       s[j + j + 1] = hex[digest[j] & 0x0f];
798     }
799   s[j + j] = '\0';
800
801   if (strcmp(s, md5sum))
802     panic("md5sum mismatch");
803 }
804 #else
805 static inline void check_md5(const char *, u_int8_t *, unsigned, const char *)
806 {}
807 #endif
808
809 typedef struct
810 {
811   l4_uint32_t  start;
812   l4_uint32_t  size;
813   l4_uint32_t  size_uncompressed;
814   l4_uint32_t  name;
815   l4_uint32_t  md5sum_compr;
816   l4_uint32_t  md5sum_uncompr;
817 } mod_info;
818
819 extern mod_info _module_info_start[];
820 extern mod_info _module_info_end[];
821
822 extern l4util_mb_mod_t _modules_mbi_start[];
823 extern l4util_mb_mod_t _modules_mbi_end[];
824
825 /**
826  * Create the basic multi-boot structure in IMAGE_MODE
827  */
828 static void
829 construct_mbi(l4util_mb_info_t *mbi)
830 {
831   unsigned i;
832   l4util_mb_mod_t *mods = _modules_mbi_start;
833 #ifdef COMPRESS
834   l4_addr_t destbuf;
835 #endif
836
837   mbi->mods_count  = _module_info_end - _module_info_start;
838   mbi->flags      |= L4UTIL_MB_MODS;
839   mbi->mods_addr   = (l4_addr_t)mods;
840
841   assert(mbi->mods_count >= 2);
842
843   for (i = 0; i < mbi->mods_count; ++i)
844     check_md5(L4_CHAR_PTR(_module_info_start[i].name),
845               (u_int8_t *)_module_info_start[i].start,
846               _module_info_start[i].size,
847               L4_CHAR_PTR(_module_info_start[i].md5sum_compr));
848
849 #ifdef COMPRESS
850   printf("Compressed modules:\n");
851   for (i = 0; i < mbi->mods_count; i++)
852     {
853       printf("  mod%02u: %08x-%08x: %s\n",
854              i, _module_info_start[i].start,
855              _module_info_start[i].start + _module_info_start[i].size,
856              L4_CHAR_PTR(_module_info_start[i].name));
857     }
858
859   destbuf = l4_round_page(mods[mbi->mods_count - 1].mod_end);
860   if (destbuf < _mod_addr)
861     destbuf = _mod_addr;
862
863   // advance to last module end
864   for (i = 0; i < mbi->mods_count; i++)
865     destbuf += l4_round_page(_module_info_start[i].size_uncompressed);
866
867   // check for overlaps and adjust mod_addr accordingly
868   unsigned long d = destbuf;
869   for (i = mbi->mods_count; i > 0; --i)
870     {
871       d -= l4_round_page(_module_info_start[i - 1].size_uncompressed);
872       if (d <= _module_info_start[i-1].start + _module_info_start[i-1].size)
873         {
874           l4_addr_t x = (_module_info_start[i-1].start + _module_info_start[i-1].size + 0xfff) & ~0xfff;
875           l4_addr_t delta = x - d;
876
877           _mod_addr += delta;
878           destbuf += delta;
879           printf("  Adjusting modaddr to %lx {%d}\n", _mod_addr, i-1);
880           d = x;
881         }
882     }
883
884   printf("Uncompressing modules (modaddr = %lx):\n", _mod_addr);
885 #endif
886
887   for (i = mbi->mods_count; i > 0; --i)
888     {
889 #ifdef COMPRESS
890       destbuf -= l4_round_page(_module_info_start[i - 1].size_uncompressed);
891
892       l4_addr_t image =
893          (l4_addr_t)decompress(L4_CONST_CHAR_PTR(_module_info_start[i - 1].name),
894                                L4_VOID_PTR(_module_info_start[i - 1].start),
895                                (void *)destbuf,
896                                _module_info_start[i - 1].size,
897                                _module_info_start[i - 1].size_uncompressed);
898 #else
899       l4_addr_t image = _module_info_start[i - 1].start;
900 #endif
901       mods[i - 1].mod_start = image;
902       mods[i - 1].mod_end   = image + _module_info_start[i - 1].size_uncompressed;
903       printf("  mod%02u: %08x-%08x: %s\n",
904              i - 1, mods[i - 1].mod_start, mods[i - 1].mod_end,
905              L4_CHAR_PTR(_module_info_start[i - 1].name));
906       if (image == 0)
907         panic("Panic: Failure decompressing image\n");
908       if (!ram.contains(Region(mods[i - 1].mod_start,
909                                mods[i - 1].mod_end)))
910         panic("Panic: Module does not fit into RAM");
911
912     }
913
914   for (i = 0; i < mbi->mods_count; ++i)
915     check_md5(L4_CHAR_PTR(_module_info_start[i].name),
916               (u_int8_t *)mods[i].mod_start,
917               _module_info_start[i].size_uncompressed,
918               L4_CHAR_PTR(_module_info_start[i].md5sum_uncompr));
919 }
920 #endif /* IMAGE_MODE */
921
922
923 void
924 init_pc_serial(l4util_mb_info_t *mbi)
925 {
926 #if defined(ARCH_x86) || defined(ARCH_amd64)
927   const char *s;
928   int comport = -1;
929
930   if ((s = check_arg(mbi, "-comport")))
931     comport = strtoul(s + 9, 0, 0);
932
933   if (check_arg(mbi, "-serial"))
934     {
935       if (0)
936         {
937           extern unsigned long search_pci_serial_devs(bool scan_only);
938           unsigned long port;
939           if (comport == -1
940               && (port = search_pci_serial_devs(false)))
941             comport = port;
942         }
943
944       if (comport == -1)
945         comport = 1;
946
947       com_cons_init(comport);
948     }
949 #else
950   (void)mbi;
951 #endif
952
953 }
954
955 #ifdef ARCH_arm
956 #ifndef IMAGE_MODE
957 // check that our is_precious_ram function can work ok
958 #error For ARM, IMAGE_MODE must always be enabled
959 #endif
960
961 /* Occupied RAM at the point we are scannig it */
962 static int
963 is_precious_ram(unsigned long addr)
964 {
965   extern int _start, _end;
966   unsigned i, c = _module_info_end - _module_info_start;
967
968   if ((unsigned long)&_start <= addr && addr <= (unsigned long)&_end)
969     return 1;
970
971   if ((unsigned long)_module_info_start <= addr
972        && addr <= (unsigned long)_module_info_end)
973     return 1;
974
975   if ((unsigned long)_modules_mbi_start <= addr
976       && addr <= (unsigned long)_modules_mbi_end)
977     return 1;
978
979   for (i = 0; i < c; ++i)
980     if (_module_info_start[i].start <= addr
981         && _module_info_start[i].start + _module_info_start[i].size_uncompressed <= addr)
982       return 1;
983
984   return 0;
985 }
986
987 unsigned long
988 scan_ram_size(unsigned long base_addr, unsigned long max_scan_size_mb)
989 {
990   // scan the RAM to find out the RAM size, note that at this point we have
991   // two regions in RAM that we cannot touch, &_start - &_end and the
992   // modules
993
994   unsigned long offset;
995   const unsigned long increment = 1 << 20; // must be multiple of (1 << 20)
996
997   printf("  Scanning up to %ld MB RAM\n", max_scan_size_mb);
998
999   // initialize memory points
1000   for (offset = increment; offset < (max_scan_size_mb << 20); offset += offset)
1001     if (!is_precious_ram(base_addr + offset))
1002       *(unsigned long *)(base_addr + offset) = 0;
1003
1004   // write something at offset 0, does it appear elsewhere?
1005   *(unsigned long *)base_addr = 0x12345678;
1006   asm volatile("" : : : "memory");
1007   for (offset = increment; offset < (max_scan_size_mb << 20); offset += offset)
1008     if (*(unsigned long *)(base_addr + offset) == 0x12345678)
1009       return offset >> 20;
1010
1011   return max_scan_size_mb;
1012 }
1013 #endif
1014
1015 /**
1016  * \brief  Startup, started from crt0.S
1017  */
1018 /* entry point */
1019 extern "C" void
1020 startup(l4util_mb_info_t *mbi, l4_umword_t flag,
1021         void *realmode_si, ptab64_mem_info_t *ptab64_info);
1022 void
1023 startup(l4util_mb_info_t *mbi, l4_umword_t flag,
1024         void *realmode_si, ptab64_mem_info_t *ptab64_info)
1025 {
1026   void *l4i;
1027   boot_info_t boot_info;
1028   l4util_mb_mod_t *mb_mod;
1029
1030   /* fire up serial port if specificed on the command line */
1031   init_pc_serial(mbi);
1032
1033   if (!Platform_base::platform)
1034     {
1035       // will we ever see this?
1036       printf("No platform found, hangup.");
1037       while (1)
1038         ;
1039     }
1040
1041   puts("\nL4 Bootstrapper");
1042   puts("  Build: #" BUILD_NR " " BUILD_DATE);
1043
1044   regions.init(__regs, sizeof(__regs)/sizeof(__regs[0]), "regions");
1045   ram.init(__ram, sizeof(__ram)/sizeof(__ram[0]), "RAM",
1046            get_memory_limit(mbi));
1047
1048 #ifdef ARCH_amd64
1049   // add the page-table on which we're running in 64bit mode
1050   regions.add(Region::n(ptab64_info->addr, ptab64_info->addr + ptab64_info->size,
1051               ".bootstrap-ptab64", Region::Boot));
1052 #else
1053   (void)ptab64_info;
1054 #endif
1055
1056 #if defined(ARCH_x86) || defined(ARCH_amd64)
1057
1058 #ifdef REALMODE_LOADING
1059   /* create synthetic multi boot info */
1060   mbi = init_loader_mbi(realmode_si);
1061 #else
1062   (void)realmode_si;
1063   assert(flag == L4UTIL_MB_VALID); /* we need to be multiboot-booted */
1064 #endif
1065
1066 #elif defined(ARCH_arm)
1067   l4util_mb_info_t my_mbi;
1068   memset(&my_mbi, 0, sizeof(my_mbi));
1069   mbi = &my_mbi;
1070
1071   (void)realmode_si;
1072   (void)flag;
1073
1074 #elif defined(ARCH_ppc32)
1075   (void)realmode_si;
1076   (void)flag;
1077
1078   l4util_mb_info_t my_mbi;
1079   L4_drivers::Of_if of_if;
1080
1081   printf("  Detecting ram size ...\n");
1082   unsigned long ram_size = of_if.detect_ramsize();
1083   printf("    Total memory size is %luMB\n", ram_size / (1024 * 1024));
1084
1085   /* setup mbi and detect OF devices */
1086   memset(&my_mbi, 0, sizeof(my_mbi));
1087   mbi = &my_mbi;
1088   unsigned long drives_addr, drives_length;
1089
1090   if (of_if.detect_devices(&drives_addr, &drives_length))
1091     {
1092       mbi->flags |= L4UTIL_MB_DRIVE_INFO;
1093       mbi->drives_addr   = drives_addr;
1094       mbi->drives_length = drives_length;
1095     }
1096   ram.add(Region::n(0x0, ram_size, ".ram", Region::Ram));
1097
1098 #else
1099 #error Unknown arch!
1100 #endif
1101
1102   setup_memory_map(mbi);
1103
1104   /* basically add the bootstrap binary to the allocated regions */
1105   init_regions();
1106
1107   /* check command line */
1108   if (check_arg(mbi, "-no-sigma0"))
1109     sigma0 = 0;
1110
1111   if (check_arg(mbi, "-no-roottask"))
1112     roottask = 0;
1113
1114   if (const char *s = check_arg(mbi, "-modaddr"))
1115     _mod_addr = strtoul(s + 9, 0, 0);
1116
1117 #ifdef IMAGE_MODE
1118   construct_mbi(mbi);
1119 #endif
1120
1121   /* move vbe and ctrl structures to a known location, it might be in the
1122    * way when moving modules around */
1123 #if defined(ARCH_x86) || defined(ARCH_amd64)
1124   if (mbi->flags & L4UTIL_MB_VIDEO_INFO)
1125     {
1126       if (mbi->vbe_mode_info)
1127         {
1128           memcpy(&__mb_vbe, L4_VOID_PTR(mbi->vbe_mode_info),
1129                  sizeof(l4util_mb_vbe_mode_t));
1130           mbi->vbe_mode_info = (l4_addr_t)&__mb_vbe;
1131         }
1132
1133       if (mbi->vbe_ctrl_info)
1134         {
1135           memcpy(&__mb_ctrl, L4_VOID_PTR(mbi->vbe_ctrl_info),
1136                  sizeof(l4util_mb_vbe_ctrl_t));
1137           mbi->vbe_ctrl_info = (l4_addr_t)&__mb_ctrl;
1138         }
1139     }
1140 #endif
1141
1142   if (_mod_addr)
1143     move_modules(mbi, _mod_addr);
1144
1145   /* We need at least two boot modules */
1146   assert(mbi->flags & L4UTIL_MB_MODS);
1147   /* We have at least the L4 kernel and the first user task */
1148   assert(mbi->mods_count >= 2);
1149   assert(mbi->mods_count <= MODS_MAX);
1150
1151   /* we're just a GRUB-booted kernel! */
1152   add_boot_modules_region(mbi);
1153
1154   if (const char *s = get_cmdline(mbi))
1155     {
1156       /* patch modules with content given at command line */
1157       while ((s = check_arg_str((char *)s, "-patch=")))
1158         patch_module(&s, mbi);
1159     }
1160
1161
1162   add_elf_regions(mbi, kernel_module, Region::Kernel);
1163
1164   if (sigma0)
1165     add_elf_regions(mbi, sigma0_module, Region::Sigma0);
1166
1167   if (roottask)
1168     add_elf_regions(mbi, roottask_module, Region::Root);
1169
1170
1171   /* copy Multiboot data structures, we still need to a safe place
1172    * before playing with memory we don't own and starting L4 */
1173   mb_info = relocate_mbi(mbi, &boot_info.mbi_low, &boot_info.mbi_high);
1174   if (!mb_info)
1175     panic("could not copy multiboot info to memory below 4MB");
1176
1177   mb_mod = (l4util_mb_mod_t*)mb_info->mods_addr;
1178
1179   /* --- Shouldn't touch original Multiboot parameters after here. -- */
1180
1181   /* setup kernel PART ONE */
1182   printf("  Loading ");
1183   print_module_name(L4_CONST_CHAR_PTR(mb_mod[kernel_module].cmdline),
1184       "[KERNEL]");
1185   putchar('\n');
1186
1187   boot_info.kernel_start = load_elf_module(mb_mod + kernel_module);
1188
1189   /* setup sigma0 */
1190   if (sigma0)
1191     {
1192       printf("  Loading ");
1193       print_module_name(L4_CONST_CHAR_PTR(mb_mod[sigma0_module].cmdline),
1194                          "[SIGMA0]");
1195       putchar('\n');
1196
1197       boot_info.sigma0_start = load_elf_module(mb_mod + sigma0_module);
1198       boot_info.sigma0_stack = (l4_addr_t)sigma0_init_stack
1199                                + sizeof(sigma0_init_stack);
1200     }
1201
1202   /* setup roottask */
1203   if (roottask)
1204     {
1205
1206       printf("  Loading ");
1207       print_module_name(L4_CONST_CHAR_PTR(mb_mod[roottask_module].cmdline),
1208                          "[ROOTTASK]");
1209       putchar('\n');
1210
1211       boot_info.roottask_start = load_elf_module(mb_mod + roottask_module);
1212       boot_info.roottask_stack = (l4_addr_t)roottask_init_stack
1213                                  + sizeof(roottask_init_stack);
1214     }
1215
1216   /* setup kernel PART TWO (special kernel initialization) */
1217   l4i = find_kip();
1218
1219 #if defined(ARCH_x86) || defined(ARCH_amd64) || defined(ARCH_ppc32)
1220   /* setup multi boot info structure for kernel */
1221   l4util_mb_info_t kernel_mbi;
1222   kernel_mbi = *mb_info;
1223   kernel_mbi.flags = L4UTIL_MB_MEMORY;
1224   if (mb_mod[kernel_module].cmdline)
1225     {
1226       kernel_mbi.cmdline = mb_mod[kernel_module].cmdline;
1227       kernel_mbi.flags  |= L4UTIL_MB_CMDLINE;
1228     }
1229 #endif
1230
1231   regions.optimize();
1232   regions.dump();
1233
1234   if (char *c = check_arg(mbi, "-presetmem="))
1235     {
1236       unsigned fill_value = strtoul(c + 11, NULL, 0);
1237       fill_mem(fill_value);
1238     }
1239
1240   /* setup the L4 kernel info page before booting the L4 microkernel:
1241    * patch ourselves into the booter task addresses */
1242   unsigned long api_version = get_api_version(l4i);
1243   unsigned major = api_version >> 24;
1244   printf("  API Version: (%x) %s\n", major, (major & 0x80)?"experimental":"");
1245   switch (major)
1246     {
1247     case 0x02: // Version 2 API
1248     case 0x03: // Version X.0 and X.1
1249     case 0x87: // Fiasco
1250       init_kip_v2(l4i, &boot_info, mb_info, &ram, &regions);
1251       //init_kip_kuart_info(l4i, &kip_kernel_uart_info);
1252       break;
1253     case 0x84:
1254     case 0x04:
1255       init_kip_v4(l4i, &boot_info, mb_info, &ram, &regions);
1256       break;
1257     default:
1258       panic("cannot boot a kernel with unknown api version %lx\n", api_version);
1259       break;
1260     }
1261
1262   printf("  Starting kernel ");
1263   print_module_name(L4_CONST_CHAR_PTR(mb_mod[kernel_module].cmdline),
1264                     "[KERNEL]");
1265   printf(" at "l4_addr_fmt"\n", boot_info.kernel_start);
1266
1267 #if defined(ARCH_x86)
1268   asm volatile
1269     ("pushl $exit ; jmp *%3"
1270      :
1271      : "a" (L4UTIL_MB_VALID),
1272        "b" (&kernel_mbi),
1273        "S" (realmode_si),
1274        "r" (boot_info.kernel_start));
1275
1276 #elif defined(ARCH_amd64)
1277
1278   asm volatile
1279     ("push $exit; jmp *%2"
1280      :
1281      : "S" (L4UTIL_MB_VALID), "D" (&kernel_mbi), "r" (boot_info.kernel_start));
1282
1283 #elif defined(ARCH_arm)
1284   typedef void (*startup_func)(void);
1285   startup_func f = (startup_func)boot_info.kernel_start;
1286   f();
1287
1288 #elif defined(ARCH_ppc32)
1289
1290   init_kip_v2_arch((l4_kernel_info_t*)l4i);
1291   printf("CPU at %lu Khz/Bus at %lu Hz\n",
1292          ((l4_kernel_info_t*)l4i)->frequency_cpu,
1293          ((l4_kernel_info_t*)l4i)->frequency_bus);
1294   typedef void (*startup_func)(l4util_mb_info_t *, unsigned long);
1295   startup_func f = (startup_func)boot_info.kernel_start;
1296   of_if.boot_finish();
1297   f(&kernel_mbi, of_if.get_prom());
1298 #else
1299
1300 #error "How to enter the kernel?"
1301
1302 #endif
1303
1304   /*NORETURN*/
1305 }
1306
1307 static int
1308 l4_exec_read_exec(void * handle,
1309                   l4_addr_t file_ofs, l4_size_t file_size,
1310                   l4_addr_t mem_addr, l4_addr_t /*v_addr*/,
1311                   l4_size_t mem_size,
1312                   exec_sectype_t section_type)
1313 {
1314   exec_task_t *exec_task = (exec_task_t*)handle;
1315   if (!mem_size)
1316     return 0;
1317
1318   if (! (section_type & EXEC_SECTYPE_ALLOC))
1319     return 0;
1320
1321   if (! (section_type & (EXEC_SECTYPE_ALLOC|EXEC_SECTYPE_LOAD)))
1322     return 0;
1323
1324   if (mem_addr < exec_task->begin)
1325     exec_task->begin = mem_addr;
1326   if (mem_addr + mem_size > exec_task->end)
1327     exec_task->end = mem_addr + mem_size;
1328
1329 #ifdef VERBOSE_LOAD
1330   printf("    [%p-%p]\n", (void *) mem_addr, (void *) (mem_addr + mem_size));
1331 #endif
1332
1333   if (!ram.contains(Region::n(mem_addr, mem_addr + mem_size)))
1334     {
1335       printf("To be loaded binary region is out of memory region.\n");
1336       printf(" Binary region: %lx - %lx\n", mem_addr, mem_addr + mem_size);
1337       dump_ram_map();
1338       panic("Binary outside memory");
1339     }
1340
1341   memcpy((void *) mem_addr,
1342          (char*)(exec_task->mod_start) + file_ofs, file_size);
1343   if (file_size < mem_size)
1344     memset((void *) (mem_addr + file_size), 0, mem_size - file_size);
1345
1346
1347   Region *f = regions.find(mem_addr);
1348   if (!f)
1349     {
1350       printf("could not find %lx\n", mem_addr);
1351       regions.dump();
1352       panic("Oops: region for module not found\n");
1353     }
1354
1355   f->name(exec_task->mod->cmdline
1356                ? L4_CONST_CHAR_PTR(exec_task->mod->cmdline)
1357                :  ".[Unknown]");
1358   return 0;
1359 }
1360
1361 static int
1362 l4_exec_add_region(void * handle,
1363                   l4_addr_t /*file_ofs*/, l4_size_t /*file_size*/,
1364                   l4_addr_t mem_addr, l4_addr_t v_addr,
1365                   l4_size_t mem_size,
1366                   exec_sectype_t section_type)
1367 {
1368   exec_task_t *exec_task = (exec_task_t*)handle;
1369
1370   if (!mem_size)
1371     return 0;
1372
1373   if (! (section_type & EXEC_SECTYPE_ALLOC))
1374     return 0;
1375
1376   if (! (section_type & (EXEC_SECTYPE_ALLOC|EXEC_SECTYPE_LOAD)))
1377     return 0;
1378
1379   regions.add(Region::n(mem_addr, mem_addr + mem_size,
1380              exec_task->mod->cmdline
1381                ? L4_CONST_CHAR_PTR(exec_task->mod->cmdline)
1382                :  ".[Unknown]", Region::Type(exec_task->type),
1383                mem_addr == v_addr ? 1 : 0));
1384   return 0;
1385 }