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;
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;
28 static const char * _net_program;
29 static void * _mbi_vbe;
30 static const char * _irq0_program;
31 static struct option _long_options[];
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;
44 // for our init code we do not care about the stack size
45 #pragma GCC diagnostic ignored "-Wframe-larger-than="
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
62 #include "initcalls.h"
63 #include "kernel_console.h"
66 #include "mem_layout.h"
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";
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;
91 // If you add options here, add them to getopt_long and help below
92 struct option Boot_info::_long_options[] FIASCO_INITDATA =
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' },
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";
145 char const *Boot_info::_modules[64] FIASCO_INITDATA =
152 NULL // Roottask configuration
155 IMPLEMENT FIASCO_INIT
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];
167 unsigned int modcount = 6, skip = 3;
168 unsigned long int memsize = 64 << 20;
169 Multiboot_info * mbi;
170 Multiboot_module * mbm;
172 char const * symbols_file = "Symbols";
173 char const * lines_file = "Lines";
174 char const * roottask_config_file = "roottask.config";
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) {
189 _modules[1] = optarg;
193 _modules[2] = optarg;
196 case 'Y': // sYmbols path
197 symbols_file = optarg;
200 case 'L': // Lines path
204 case 'C': // roottask Configuration file
205 roottask_config_file = optarg;
209 if (modcount < sizeof (_modules) / sizeof (*_modules))
210 _modules[modcount++] = optarg;
212 printf("WARNING: max modules exceeded (dropped '%s')\n",
217 physmem_file = optarg;
225 kmemsize(atol(optarg) << 10);
229 memsize = atol (optarg) << 20;
234 Kconsole::console()->change_state(0, 0, ~Console::OUTENABLED, 0);
238 Config::tbuf_entries = atol (optarg);
246 _irq0_disabled = true;
250 _fb_program = optarg;
254 if (sscanf (optarg, "%ux%u@%u", &_fb_width, &_fb_height, &_fb_depth)
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
261 _input_size = Config::PAGE_SIZE;
270 _net_program = optarg;
274 _irq0_program = optarg;
278 modcount = 0; skip = 0;
286 printf ("Usage: %s\n\n%s", *__libc_argv, _help);
287 exit (arg == 'h' ? EXIT_SUCCESS : EXIT_FAILURE);
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)
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);
305 // Check roottask command line for symbols and lines options
307 if (strstr (_modules[2], " -symbols"))
309 _modules[3] = symbols_file;
312 if (strstr (_modules[2], " -lines"))
314 _modules[4] = lines_file;
317 if (strstr (_modules[2], " -configfile"))
319 _modules[5] = roottask_config_file;
325 panic("uname: %s", strerror (errno));
328 printf ("\n\nFiasco-UX on %s %s (%s)\n",
329 uts.sysname, uts.release, uts.machine);
331 get_minimum_map_address();
333 if ((_fd = open (physmem_file, O_RDWR | O_CREAT | O_EXCL | O_TRUNC, 0700))
335 panic ("cannot create physmem: %s", strerror (errno));
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))
340 unlink (physmem_file);
341 panic ("Invalid permissions for physmem file");
344 struct statvfs stvfs;
345 if (statvfs(physmem_file, &stvfs) < 0)
348 panic("Cannot query statistics on physmem file");
351 unlink (physmem_file);
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)
361 if (memsize > 1 << 30)
365 if (memsize + _fb_size + _input_size > stvfs.f_bavail * stvfs.f_bsize)
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);
371 // The framebuffer starts beyond the physical memory
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));
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));
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);
392 mbi->flags = Multiboot_info::Memory | Multiboot_info::Cmdline |
393 Multiboot_info::Mods;
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);
401 // Copying of modules starts at the top, right below the kmem reserved area
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);
410 // Load/copy the modules
411 for (m = _modules; m < _modules + modcount; m++)
413 unsigned long start, end;
419 // Cut off between module name and command line
420 if ((cmd = strchr (const_cast<char *>(*m), ' ')))
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);
437 printf ("%s: %s\n", error, *m);
441 // Reattach command line
445 mbm->string = str - (char *) mbi + mbi_phys();
447 // Copy module name with path and command line
448 str = stpcpy (str, *m) + 1;
450 // sigma0: save memory region
451 if (m == _modules + 1)
453 _sigma0_start = start;
457 // roottask: save memory region and pass in the extra command line
458 if (m == _modules + 2)
463 str = stpcpy (str, buffer) + 1;
471 puts ("\nBootstrapping...");
476 Boot_info::get_minimum_map_address()
478 FILE *f = fopen("/proc/sys/vm/mmap_min_addr", "r");
482 int r = fscanf(f, "%ld", &_min_mappable_address);
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
490 _min_mappable_address = 0x10000;
492 _min_mappable_address
493 = (_min_mappable_address + (Config::PAGE_SIZE - 1)) & Config::PAGE_MASK;
498 Boot_info::reset_checksum_ro()
501 IMPLEMENT inline NEEDS ["mem_layout.h"]
503 Boot_info::mbi_phys()
505 return Mem_layout::Multiboot_frame;
508 IMPLEMENT inline NEEDS ["mem_layout.h"]
510 Boot_info::mbi_virt()
512 return reinterpret_cast<Multiboot_info * const>
513 (Mem_layout::Physmem + mbi_phys());
517 Multiboot_vbe_controller *
520 return reinterpret_cast<Multiboot_vbe_controller *>(_mbi_vbe);
525 Boot_info::mbi_size()
527 return (unsigned long)mbi_vbe()
528 + sizeof (Multiboot_vbe_controller) + sizeof (Multiboot_vbe_mode)
529 - (unsigned long)mbi_virt();
549 Boot_info::irq0_disabled()
550 { return _irq0_disabled; }
554 Boot_info::input_start()
555 { return fb_virt() + fb_size(); }
559 Boot_info::input_size()
560 { return _input_size; }
579 Boot_info::fb_width()
580 { return _fb_width; }
584 Boot_info::fb_height()
585 { return _fb_height; }
589 Boot_info::fb_depth()
590 { return _fb_depth; }
594 Boot_info::fb_program()
595 { return _fb_program; }
599 Boot_info::net_program()
600 { return _net_program; }
609 Boot_info::irq0_path()
610 { return _irq0_program; }
614 Boot_info::emulate_clisti()
615 { return _emulate_clisti; }
619 Boot_info::sigma0_start()
620 { return _sigma0_start; }
624 Boot_info::sigma0_end()
625 { return _sigma0_end; }
629 Boot_info::root_start()
630 { return _root_start; }
634 Boot_info::root_end()
635 { return _root_end; }
639 Boot_info::min_mappable_address()
640 { return _min_mappable_address; }
644 Boot_info::get_checksum_ro(void)
649 Boot_info::get_checksum_rw(void)
655 Boot_info::set_wait()
656 { Koptions::o()->flags |= Koptions::F_wait; }
660 Boot_info::kmemsize(unsigned int k)
661 { Koptions::o()->kmemsize = k; }
665 Boot_info::set_jdb_cmd(const char *j)
667 strncpy(Koptions::o()->jdb_cmd, j, sizeof(Koptions::o()->jdb_cmd));
668 Koptions::o()->jdb_cmd[sizeof(Koptions::o()->jdb_cmd) - 1] = 0;