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