]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ux/boot_info-ux.cpp
4c47a668fb4a7cf8562d2a2c0d6114cced7dd048
[l4.git] / kernel / fiasco / src / kern / ux / boot_info-ux.cpp
1 /*
2  * Fiasco-UX
3  * Architecture specific bootinfo code
4  */
5
6 INTERFACE:
7
8 #include <sys/types.h>                  // for pid_t
9 #include <getopt.h>                     // for struct option
10 #include "l4_types.h"                   // for Global_id
11
12 EXTENSION class Boot_info
13 {
14 private:
15   static int                            _fd;            // Physmem FD
16   static pid_t                          _pid;           // Process ID
17   static char **                        _args;          // Cmd Line Parameters
18   static bool                           _irq0_disabled;
19   static bool                           _wait;
20   static unsigned long                  _input_size;
21   static unsigned long                  _kmemsize;
22   static unsigned long                  _fb_size;
23   static Address                        _fb_virt;
24   static Address                        _fb_phys;
25   static unsigned int                   _fb_width;
26   static unsigned int                   _fb_height;
27   static unsigned int                   _fb_depth;
28   static const char *                   _fb_program;
29   static bool                           _net;
30   static const char *                   _net_program;
31   static void *                         _mbi_vbe;
32   static const char *                   _irq0_program;
33   static const char *                   _jdb_cmd;
34   static struct option                  _long_options[];
35   static char                           _help[];
36   static char const *                   _modules[];
37   static bool                           _emulate_clisti;
38   static unsigned long                  _sigma0_start;
39   static unsigned long                  _sigma0_end;
40   static unsigned long                  _root_start;
41   static unsigned long                  _root_end;
42   static unsigned long                  _min_mappable_address;
43 };
44
45 IMPLEMENTATION[ux]:
46
47 // for our init code we do not care about the stack size
48 #pragma GCC diagnostic ignored "-Wframe-larger-than="
49
50 #include <cassert>                      // for assert
51 #include <cerrno>                       // for errno
52 #include <climits>                      // for CHAR_BIT
53 #include <cstdlib>                      // for atol
54 #include <cstring>                      // for stpcpy
55 #include <cstdio>                       // for printf
56 #include <fcntl.h>                      // for open
57 #include <panic.h>                      // for panic
58 #include <unistd.h>                     // for getopt
59 #include <sys/mman.h>                   // for mmap
60 #include <sys/stat.h>                   // for open
61 #include <sys/statvfs.h>
62 #include <sys/utsname.h>                // for uname
63
64 #include "config.h"
65 #include "initcalls.h"
66 #include "kernel_console.h"
67 #include "loader.h"
68 #include "mem_layout.h"
69
70 int                     Boot_info::_fd;
71 pid_t                   Boot_info::_pid;
72 char **                 Boot_info::_args;
73 bool                    Boot_info::_irq0_disabled;
74 bool                    Boot_info::_wait;
75 unsigned long           Boot_info::_input_size;
76 unsigned long           Boot_info::_kmemsize;
77 unsigned long           Boot_info::_fb_size;
78 Address                 Boot_info::_fb_virt = 0xc0000000;
79 Address                 Boot_info::_fb_phys;
80 unsigned int            Boot_info::_fb_width;
81 unsigned int            Boot_info::_fb_height;
82 unsigned int            Boot_info::_fb_depth;
83 const char *            Boot_info::_fb_program = "ux_con";
84 bool                    Boot_info::_net;
85 const char *            Boot_info::_net_program = "ux_net";
86 void *                  Boot_info::_mbi_vbe;
87 const char *            Boot_info::_irq0_program = "irq0";
88 const char *            Boot_info::_jdb_cmd;
89 bool                    Boot_info::_emulate_clisti;
90 unsigned long           Boot_info::_sigma0_start;
91 unsigned long           Boot_info::_sigma0_end;
92 unsigned long           Boot_info::_root_start;
93 unsigned long           Boot_info::_root_end;
94 unsigned long           Boot_info::_min_mappable_address;
95
96 // If you add options here, add them to getopt_long and help below
97 struct option Boot_info::_long_options[] FIASCO_INITDATA =
98 {
99   { "physmem_file",             required_argument,      NULL, 'f' },
100   { "help",                     no_argument,            NULL, 'h' },
101   { "jdb_cmd",                  required_argument,      NULL, 'j' },
102   { "kmemsize",                 required_argument,      NULL, 'k' },
103   { "load_module",              required_argument,      NULL, 'l' },
104   { "memsize",                  required_argument,      NULL, 'm' },
105   { "native_task",              required_argument,      NULL, 'n' },
106   { "quiet",                    no_argument,            NULL, 'q' },
107   { "tbuf_entries",             required_argument,      NULL, 't' },
108   { "wait",                     no_argument,            NULL, 'w' },
109   { "fb_program",               required_argument,      NULL, 'F' },
110   { "fb_geometry",              required_argument,      NULL, 'G' },
111   { "net",                      no_argument,            NULL, 'N' },
112   { "net_program",              required_argument,      NULL, 'E' },
113   { "irq0",                     required_argument,      NULL, 'I' },
114   { "roottask",                 required_argument,      NULL, 'R' },
115   { "sigma0",                   required_argument,      NULL, 'S' },
116   { "test",                     no_argument,            NULL, 'T' },
117   { "disable_irq0",             no_argument,            NULL, '0' },
118   { "symbols",                  required_argument,      NULL, 'Y' },
119   { "roottaskconfig",           required_argument,      NULL, 'C' },
120   { "lines",                    required_argument,      NULL, 'L' },
121   { "clisti",                   no_argument,            NULL, 's' },
122   { 0, 0, 0, 0 }
123 };
124
125 // Keep this in sync with the options above
126 char Boot_info::_help[] FIASCO_INITDATA =
127   "-f file     : Specify the location of the physical memory backing store\n"
128   "-l module   : Specify a module\n"
129   "-j jdb cmds : Specify non-interactive Jdb commands to be executed at startup\n"
130   "-k kmemsize : Specify size in MB to be reserved for kernel\n"
131   "-m memsize  : Specify physical memory size in MB (currently up to 1024)\n"
132   "-q          : Suppress any startup message\n"
133   "-t number   : Specify the number of trace buffer entries (up to 32768)\n"
134   "-w          : Enter kernel debugger on startup and wait\n"
135   "-0          : Disable the timer interrupt generator\n"
136   "-F          : Specify a different frame buffer program\n"
137   "-G          : Geometry for frame buffer: widthxheight@depth\n"
138   "-N          : Enable network support\n"
139   "-E          : Specify net helper binary\n"
140   "-I          : Specify different irq0 binary\n"
141   "-R          : Specify different roottask binary\n"
142   "-S          : Specify different sigma0 binary\n"
143   "-Y          : Specify symbols path\n"
144   "-L          : Specify lines path\n"
145   "-C          : Specify roottask configuration file path\n"
146   "-T          : Test mode -- do not load any modules\n"
147   "-s          : Emulate cli/sti instructions\n";
148
149
150 char const *Boot_info::_modules[64] FIASCO_INITDATA =
151 {
152   "fiasco",
153   "sigma0",
154   "moe",
155    NULL,        // Symbols
156    NULL,        // Lines
157    NULL         // Roottask configuration
158 };
159
160 IMPLEMENT FIASCO_INIT
161 void
162 Boot_info::init()
163 {
164   extern int                    __libc_argc;
165   extern char **                __libc_argv;
166   register unsigned long        _sp asm("esp");
167   char const                    *physmem_file = "/tmp/physmem";
168   char const                    *error, **m;
169   char                          *str, buffer[4096];
170   int                           arg;
171   bool                          quiet = false;
172   unsigned int                  modcount = 6, skip = 3;
173   unsigned long int             memsize = 64 << 20;
174   Multiboot_info *              mbi;
175   Multiboot_module *            mbm;
176   struct utsname                uts;
177   char const *                  symbols_file = "Symbols";
178   char const *                  lines_file = "Lines";
179   char const *                  roottask_config_file = "roottask.config";
180
181   _args = __libc_argv;
182   _pid  = getpid ();
183
184   *(str = buffer) = 0;
185
186   // Parse command line. Use getopt_long_only() to achieve more compatibility
187   // with command line switches in the IA32 architecture.
188   while ((arg = getopt_long_only (__libc_argc, __libc_argv,
189                                   "C:f:hj:k:l:m:qst:wE:F:G:I:L:NR:S:TY:0",
190                                   _long_options, NULL)) != -1) {
191     switch (arg) {
192
193       case 'S':
194         _modules[1] = optarg;
195         break;
196
197       case 'R':
198         _modules[2] = optarg;
199         break;
200
201       case 'Y': // sYmbols path
202         symbols_file = optarg;
203         break;
204
205       case 'L': // Lines path
206         lines_file = optarg;
207         break;
208
209       case 'C': // roottask Configuration file
210         roottask_config_file = optarg;
211         break;
212
213       case 'l':
214         if (modcount < sizeof (_modules) / sizeof (*_modules))
215           _modules[modcount++] = optarg;
216         else
217           printf("WARNING: max modules exceeded (dropped '%s')\n",
218               optarg);
219         break;
220
221       case 'f':
222         physmem_file = optarg;
223         break;
224
225       case 'j':
226         _jdb_cmd = optarg;
227         break;
228
229       case 'k':
230         _kmemsize = atol (optarg) << 20;
231         break;
232
233       case 'm':
234         memsize = atol (optarg) << 20;
235         break;
236
237       case 'q':
238         quiet = true;
239         Kconsole::console()->change_state(0, 0, ~Console::OUTENABLED, 0);
240         break;
241
242       case 't':
243         Config::tbuf_entries = atol (optarg);
244         break;
245
246       case 'w':
247         _wait = true;
248         break;
249
250       case '0':
251         _irq0_disabled = true;
252         break;
253
254       case 'F':
255         _fb_program = optarg;
256         break;
257
258       case 'G':
259         if (sscanf (optarg, "%ux%u@%u", &_fb_width, &_fb_height, &_fb_depth)
260             == 3)
261           {
262             _fb_size = _fb_width * _fb_height * (_fb_depth + 7 >> 3);
263             _fb_size += ~Config::SUPERPAGE_MASK;
264             _fb_size &=  Config::SUPERPAGE_MASK;        // Round up to 4 MB
265
266             _input_size  = Config::PAGE_SIZE;
267           }
268         break;
269
270       case 'N':
271         _net = 1;
272         break;
273
274       case 'E':
275         _net_program = optarg;
276         break;
277
278       case 'I':
279         _irq0_program = optarg;
280         break;
281
282       case 'T':
283         modcount = 0; skip = 0;
284         break;
285
286       case 's':
287         _emulate_clisti = 1;
288         break;
289
290       default:
291         printf ("Usage: %s\n\n%s", *__libc_argv, _help);
292         exit (arg == 'h' ? EXIT_SUCCESS : EXIT_FAILURE);
293     }
294   }
295
296   if (_sp < ((Mem_layout::Host_as_base - 1) & Config::SUPERPAGE_MASK)
297       && munmap((void *)((Mem_layout::Host_as_base - 1) & Config::PAGE_MASK),
298                 Config::PAGE_SIZE) == -1 && errno == EINVAL)
299     {
300       printf(" Fiasco-UX does only run with %dGB user address space size.\n"
301              " Please make sure your host Linux kernel is configured for %dGB\n"
302              " user address space size. Check for\n"
303              "     CONFIG_PAGE_OFFSET=0x%X\n"
304              " in your host Linux .config.\n",
305              Mem_layout::Host_as_base >> 30, Mem_layout::Host_as_base >> 30,
306              Mem_layout::Host_as_base);
307       exit(EXIT_FAILURE);
308     }
309
310   // Check roottask command line for symbols and lines options
311 #if 0
312   if (strstr (_modules[2], " -symbols"))
313     {
314       _modules[3] = symbols_file;
315       skip--;
316     }
317   if (strstr (_modules[2], " -lines"))
318     {
319       _modules[4] = lines_file;
320       skip--;
321     }
322   if (strstr (_modules[2], " -configfile"))
323     {
324       _modules[5] = roottask_config_file;
325       skip--;
326     }
327 #endif
328
329   if (uname (&uts))
330     panic("uname: %s", strerror (errno));
331
332   if (! quiet)
333     printf ("\n\nFiasco-UX on %s %s (%s)\n",
334             uts.sysname, uts.release, uts.machine);
335
336   get_minimum_map_address();
337
338   if ((_fd = open (physmem_file, O_RDWR | O_CREAT | O_EXCL | O_TRUNC, 0700))
339       == -1)
340     panic ("cannot create physmem: %s", strerror (errno));
341
342   // check if we really got exec-rights on physmem, /tmp might be mounted noexec
343   if (access(physmem_file, R_OK | W_OK | X_OK))
344     {
345       unlink (physmem_file);
346       panic ("Invalid permissions for physmem file");
347     }
348
349   struct statvfs stvfs;
350   if (statvfs(physmem_file, &stvfs) < 0)
351     {
352       perror("statvfs");
353       panic("Cannot query statistics on physmem file");
354     }
355
356   unlink (physmem_file);
357
358   // Cannot handle more physical memory than roottask can handle (currently 1 GB).
359   // roottask considers anything greater than 0x40000000 as adapter page.
360 #ifdef CONFIG_CONTEXT_4K
361   // With 4k kernel thread context size we cannot handle more than 512MB
362   // physical memory (mapped to the virtual area 0x90000000..0xb0000000).
363   if (memsize > 1 << 29)
364     memsize = 1 << 29;
365 #else
366   if (memsize > 1 << 30)
367     memsize = 1 << 30;
368 #endif
369
370   if (memsize + _fb_size + _input_size > stvfs.f_bavail * stvfs.f_bsize)
371     {
372       printf("WARNING: Available free space of %ldMB for '%s' might not be enough.\n",
373              (stvfs.f_bavail * stvfs.f_bsize) >> 20, physmem_file);
374     }
375
376   // The framebuffer starts beyond the physical memory
377   _fb_phys = memsize;
378
379   // Create a sparse file as backing store
380   if (lseek (_fd, memsize + _fb_size + _input_size - 1, SEEK_SET) == -1 ||
381       write (_fd, "~", 1) != 1)
382     panic ("cannot resize physmem: %s", strerror (errno));
383
384   // Now map the beast in our virtual address space
385   if (mmap (reinterpret_cast<void *>(Mem_layout::Physmem),
386             memsize + _fb_size + _input_size,
387             PROT_READ | PROT_WRITE,
388             MAP_FIXED | MAP_SHARED, _fd, 0) == MAP_FAILED)
389     panic ("cannot mmap physmem: %s", strerror (errno));
390
391   if (! quiet)
392     printf ("Mapped %lu MB Memory + %lu KB Framebuffer + "
393             "%lu KB Input Area on FD %d\n\n",
394             memsize >> 20, _fb_size >> 10, _input_size >> 10, _fd);
395
396   mbi             = mbi_virt();
397   mbi->flags      = Multiboot_info::Memory | Multiboot_info::Cmdline |
398                     Multiboot_info::Mods;
399   mbi->mem_lower  = 0;
400   mbi->mem_upper  = (memsize >> 10) - 1024;            /* in KB */
401   mbi->mods_count = modcount - skip;
402   mbi->mods_addr  = mbi_phys() + sizeof (*mbi);
403   mbm = reinterpret_cast<Multiboot_module *>((char *) mbi + sizeof (*mbi));
404   str = reinterpret_cast<char *>(mbm + modcount - skip);
405
406   // Copying of modules starts at the top, right below the kmem reserved area
407
408   // Skip an area of 1MB in order to allow sigma0 to allocate its memmap
409   // structures at top of physical memory. Note that the space the boot
410   // modules are loaded at is later freed in most cases so we prevent memory
411   // fragmentation here.
412   Address load_addr = kmem_start (0xffffffff) - (1 << 20);
413
414
415   // Load/copy the modules
416   for (m = _modules; m < _modules + modcount; m++)
417     {
418       unsigned long start, end;
419       char *cmd;
420
421       if (!*m)
422         continue;
423
424       // Cut off between module name and command line
425       if ((cmd = strchr (const_cast<char *>(*m), ' ')))
426         *cmd = 0;
427
428       if (m == _modules)
429         {
430           mbm->mod_start = 0;
431           mbm->mod_end = 0;
432           error = 0;
433         }
434       else
435         // Load sigma0 and roottask, just copy the rest
436         error = m < _modules + 3 ?
437               Loader::load_module (*m, mbm, memsize, quiet, &start, &end) :
438               Loader::copy_module (*m, mbm, &load_addr, quiet);
439
440       if (error)
441         {
442           printf ("%s: %s\n", error, *m);
443           exit (EXIT_FAILURE);
444         }
445
446       // Reattach command line
447       if (cmd)
448         *cmd = ' ';
449
450       mbm->string = str - (char *) mbi + mbi_phys();
451
452       // Copy module name with path and command line
453       str = stpcpy (str, *m) + 1;
454
455       // sigma0: save memory region
456       if (m == _modules + 1)
457         {
458           _sigma0_start = start;
459           _sigma0_end   = end;
460         }
461       else
462       // roottask: save memory region and pass in the extra command line
463       if (m == _modules + 2)
464         {
465           _root_start = start;
466           _root_end   = end;
467           str--;
468           str = stpcpy (str, buffer) + 1;
469         }
470
471       mbm++;
472     }
473   _mbi_vbe = str;
474
475   if (! quiet)
476     puts ("\nBootstrapping...");
477 }
478
479 PRIVATE static
480 void
481 Boot_info::get_minimum_map_address()
482 {
483   FILE *f = fopen("/proc/sys/vm/mmap_min_addr", "r");
484   if (!f)
485     return;
486
487   int r = fscanf(f, "%ld", &_min_mappable_address);
488   fclose(f);
489
490   // funny thing is that although /proc/sys/vm/mmap_min_addr might be
491   // readable according to the file permissions it might not actually work
492   // (a read returns EPERM, seen with 2.6.33), since at at least Ubuntu sets
493   // mmap_min_addr to 0x10000 we take this as the default value here
494   if (r == -1)
495     _min_mappable_address = 0x10000;
496
497   _min_mappable_address
498     = (_min_mappable_address + (Config::PAGE_SIZE - 1)) & Config::PAGE_MASK;
499 }
500
501 PUBLIC static inline
502 void
503 Boot_info::reset_checksum_ro()
504 {}
505
506 IMPLEMENT inline NEEDS ["mem_layout.h"]
507 Address
508 Boot_info::mbi_phys()
509 {
510   return Mem_layout::Multiboot_frame;
511 }
512
513 IMPLEMENT inline NEEDS ["mem_layout.h"]
514 Multiboot_info *
515 Boot_info::mbi_virt()
516 {
517   return reinterpret_cast<Multiboot_info * const>
518     (Mem_layout::Physmem + mbi_phys());
519 }
520
521 PUBLIC static inline
522 Multiboot_vbe_controller *
523 Boot_info::mbi_vbe()
524 {
525   return reinterpret_cast<Multiboot_vbe_controller *>(_mbi_vbe);
526 }
527
528 PUBLIC static inline
529 unsigned long 
530 Boot_info::mbi_size()
531 {
532   return (unsigned long)mbi_vbe() 
533     + sizeof (Multiboot_vbe_controller) + sizeof (Multiboot_vbe_mode) 
534     - (unsigned long)mbi_virt();
535 }
536
537 PUBLIC static inline
538 int
539 Boot_info::fd()
540 { return _fd; }
541
542 PUBLIC static inline
543 pid_t
544 Boot_info::pid()
545 { return _pid; }
546
547 PUBLIC static inline
548 char **
549 Boot_info::args()
550 { return _args; }
551
552 PUBLIC static inline
553 bool
554 Boot_info::irq0_disabled()
555 { return _irq0_disabled; }
556
557 PUBLIC static inline
558 bool
559 Boot_info::wait()
560 { return _wait; }
561
562 PUBLIC static inline
563 unsigned long
564 Boot_info::input_start()
565 { return fb_virt() + fb_size(); }
566
567 PUBLIC static inline
568 unsigned long
569 Boot_info::input_size()
570 { return _input_size; }
571
572 PUBLIC static inline
573 unsigned long
574 Boot_info::fb_size()
575 { return _fb_size; }
576
577 PUBLIC static inline
578 Address
579 Boot_info::fb_virt()
580 { return _fb_virt; }
581
582 PUBLIC static inline
583 Address
584 Boot_info::fb_phys()
585 { return _fb_phys; }
586
587 PUBLIC static inline
588 unsigned int
589 Boot_info::fb_width()
590 { return _fb_width; }
591
592 PUBLIC static inline
593 unsigned int
594 Boot_info::fb_height()
595 { return _fb_height; }
596
597 PUBLIC static inline
598 unsigned int
599 Boot_info::fb_depth()
600 { return _fb_depth; }
601
602 PUBLIC static inline
603 const char *
604 Boot_info::fb_program()
605 { return _fb_program; }
606
607 PUBLIC static inline
608 const char *
609 Boot_info::net_program()
610 { return _net_program; }
611
612 PUBLIC static inline
613 bool
614 Boot_info::net()
615 { return _net; }
616
617 PUBLIC static inline
618 const char *
619 Boot_info::irq0_path()
620 { return _irq0_program; }
621
622 PUBLIC static inline
623 const char *
624 Boot_info::jdb_cmd()
625 { return _jdb_cmd; }
626
627 PUBLIC static inline
628 unsigned long
629 Boot_info::kmemsize()
630 { return _kmemsize; }
631
632 PUBLIC static inline
633 bool
634 Boot_info::emulate_clisti()
635 { return _emulate_clisti; }
636
637 PUBLIC static inline
638 unsigned long
639 Boot_info::sigma0_start()
640 { return _sigma0_start; }
641
642 PUBLIC static inline
643 unsigned long
644 Boot_info::sigma0_end()
645 { return _sigma0_end; }
646
647 PUBLIC static inline
648 unsigned long
649 Boot_info::root_start()
650 { return _root_start; }
651
652 PUBLIC static inline
653 unsigned long
654 Boot_info::root_end()
655 { return _root_end; }
656
657 PUBLIC static inline
658 unsigned long
659 Boot_info::min_mappable_address()
660 { return _min_mappable_address; }
661
662 PUBLIC inline static
663 unsigned
664 Boot_info::get_checksum_ro(void)
665 { return 0; }
666
667 PUBLIC inline static
668 unsigned
669 Boot_info::get_checksum_rw(void)
670 { return 0; }
671