3 * Architecture specific bootinfo code
8 #include <sys/types.h> // for pid_t
9 #include <getopt.h> // for struct option
10 #include "l4_types.h" // for Global_id
12 EXTENSION class Boot_info
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;
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;
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[];
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;
47 // for our init code we do not care about the stack size
48 #pragma GCC diagnostic ignored "-Wframe-larger-than="
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
65 #include "initcalls.h"
66 #include "kernel_console.h"
68 #include "mem_layout.h"
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";
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;
96 // If you add options here, add them to getopt_long and help below
97 struct option Boot_info::_long_options[] FIASCO_INITDATA =
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' },
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";
150 char const *Boot_info::_modules[64] FIASCO_INITDATA =
157 NULL // Roottask configuration
160 IMPLEMENT FIASCO_INIT
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];
172 unsigned int modcount = 6, skip = 3;
173 unsigned long int memsize = 64 << 20;
174 Multiboot_info * mbi;
175 Multiboot_module * mbm;
177 char const * symbols_file = "Symbols";
178 char const * lines_file = "Lines";
179 char const * roottask_config_file = "roottask.config";
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) {
194 _modules[1] = optarg;
198 _modules[2] = optarg;
201 case 'Y': // sYmbols path
202 symbols_file = optarg;
205 case 'L': // Lines path
209 case 'C': // roottask Configuration file
210 roottask_config_file = optarg;
214 if (modcount < sizeof (_modules) / sizeof (*_modules))
215 _modules[modcount++] = optarg;
217 printf("WARNING: max modules exceeded (dropped '%s')\n",
222 physmem_file = optarg;
230 _kmemsize = atol (optarg) << 20;
234 memsize = atol (optarg) << 20;
239 Kconsole::console()->change_state(0, 0, ~Console::OUTENABLED, 0);
243 Config::tbuf_entries = atol (optarg);
251 _irq0_disabled = true;
255 _fb_program = optarg;
259 if (sscanf (optarg, "%ux%u@%u", &_fb_width, &_fb_height, &_fb_depth)
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
266 _input_size = Config::PAGE_SIZE;
275 _net_program = optarg;
279 _irq0_program = optarg;
283 modcount = 0; skip = 0;
291 printf ("Usage: %s\n\n%s", *__libc_argv, _help);
292 exit (arg == 'h' ? EXIT_SUCCESS : EXIT_FAILURE);
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)
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);
310 // Check roottask command line for symbols and lines options
312 if (strstr (_modules[2], " -symbols"))
314 _modules[3] = symbols_file;
317 if (strstr (_modules[2], " -lines"))
319 _modules[4] = lines_file;
322 if (strstr (_modules[2], " -configfile"))
324 _modules[5] = roottask_config_file;
330 panic("uname: %s", strerror (errno));
333 printf ("\n\nFiasco-UX on %s %s (%s)\n",
334 uts.sysname, uts.release, uts.machine);
336 get_minimum_map_address();
338 if ((_fd = open (physmem_file, O_RDWR | O_CREAT | O_EXCL | O_TRUNC, 0700))
340 panic ("cannot create physmem: %s", strerror (errno));
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))
345 unlink (physmem_file);
346 panic ("Invalid permissions for physmem file");
349 struct statvfs stvfs;
350 if (statvfs(physmem_file, &stvfs) < 0)
353 panic("Cannot query statistics on physmem file");
356 unlink (physmem_file);
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)
366 if (memsize > 1 << 30)
370 if (memsize + _fb_size + _input_size > stvfs.f_bavail * stvfs.f_bsize)
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);
376 // The framebuffer starts beyond the physical memory
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));
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));
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);
397 mbi->flags = Multiboot_info::Memory | Multiboot_info::Cmdline |
398 Multiboot_info::Mods;
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);
406 // Copying of modules starts at the top, right below the kmem reserved area
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);
415 // Load/copy the modules
416 for (m = _modules; m < _modules + modcount; m++)
418 unsigned long start, end;
424 // Cut off between module name and command line
425 if ((cmd = strchr (const_cast<char *>(*m), ' ')))
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);
442 printf ("%s: %s\n", error, *m);
446 // Reattach command line
450 mbm->string = str - (char *) mbi + mbi_phys();
452 // Copy module name with path and command line
453 str = stpcpy (str, *m) + 1;
455 // sigma0: save memory region
456 if (m == _modules + 1)
458 _sigma0_start = start;
462 // roottask: save memory region and pass in the extra command line
463 if (m == _modules + 2)
468 str = stpcpy (str, buffer) + 1;
476 puts ("\nBootstrapping...");
481 Boot_info::get_minimum_map_address()
483 FILE *f = fopen("/proc/sys/vm/mmap_min_addr", "r");
487 int r = fscanf(f, "%ld", &_min_mappable_address);
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
495 _min_mappable_address = 0x10000;
497 _min_mappable_address
498 = (_min_mappable_address + (Config::PAGE_SIZE - 1)) & Config::PAGE_MASK;
503 Boot_info::reset_checksum_ro()
506 IMPLEMENT inline NEEDS ["mem_layout.h"]
508 Boot_info::mbi_phys()
510 return Mem_layout::Multiboot_frame;
513 IMPLEMENT inline NEEDS ["mem_layout.h"]
515 Boot_info::mbi_virt()
517 return reinterpret_cast<Multiboot_info * const>
518 (Mem_layout::Physmem + mbi_phys());
522 Multiboot_vbe_controller *
525 return reinterpret_cast<Multiboot_vbe_controller *>(_mbi_vbe);
530 Boot_info::mbi_size()
532 return (unsigned long)mbi_vbe()
533 + sizeof (Multiboot_vbe_controller) + sizeof (Multiboot_vbe_mode)
534 - (unsigned long)mbi_virt();
554 Boot_info::irq0_disabled()
555 { return _irq0_disabled; }
564 Boot_info::input_start()
565 { return fb_virt() + fb_size(); }
569 Boot_info::input_size()
570 { return _input_size; }
589 Boot_info::fb_width()
590 { return _fb_width; }
594 Boot_info::fb_height()
595 { return _fb_height; }
599 Boot_info::fb_depth()
600 { return _fb_depth; }
604 Boot_info::fb_program()
605 { return _fb_program; }
609 Boot_info::net_program()
610 { return _net_program; }
619 Boot_info::irq0_path()
620 { return _irq0_program; }
629 Boot_info::kmemsize()
630 { return _kmemsize; }
634 Boot_info::emulate_clisti()
635 { return _emulate_clisti; }
639 Boot_info::sigma0_start()
640 { return _sigma0_start; }
644 Boot_info::sigma0_end()
645 { return _sigma0_end; }
649 Boot_info::root_start()
650 { return _root_start; }
654 Boot_info::root_end()
655 { return _root_end; }
659 Boot_info::min_mappable_address()
660 { return _min_mappable_address; }
664 Boot_info::get_checksum_ro(void)
669 Boot_info::get_checksum_rw(void)