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