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 "emulation.h"
63 #include "initcalls.h"
64 #include "kernel_console.h"
67 #include "mem_layout.h"
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";
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;
92 // If you add options here, add them to getopt_long and help below
93 struct option Boot_info::_long_options[] FIASCO_INITDATA =
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' },
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";
146 char const *Boot_info::_modules[64] FIASCO_INITDATA =
153 NULL // Roottask configuration
156 IMPLEMENT FIASCO_INIT
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];
168 unsigned int modcount = 6, skip = 3;
169 unsigned long int memsize = 64 << 20;
170 Multiboot_info * mbi;
171 Multiboot_module * mbm;
174 char const * symbols_file = "Symbols";
175 char const * lines_file = "Lines";
176 char const * roottask_config_file = "roottask.config";
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) {
192 _modules[1] = optarg;
196 _modules[2] = optarg;
199 case 'Y': // sYmbols path
201 symbols_file = optarg;
205 case 'L': // Lines path
211 case 'C': // roottask Configuration file
213 roottask_config_file = optarg;
218 if (modcount < sizeof (_modules) / sizeof (*_modules))
219 _modules[modcount++] = optarg;
221 printf("WARNING: max modules exceeded (dropped '%s')\n",
226 physmem_file = optarg;
234 kmemsize(atol(optarg) << 10);
238 memsize = atol (optarg) << 20;
243 Kconsole::console()->change_state(0, 0, ~Console::OUTENABLED, 0);
247 Config::tbuf_entries = atol (optarg);
255 _irq0_disabled = true;
259 _fb_program = optarg;
263 if (sscanf (optarg, "%ux%u@%u", &_fb_width, &_fb_height, &_fb_depth)
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
270 _input_size = Config::PAGE_SIZE;
279 _net_program = optarg;
283 _irq0_program = optarg;
287 modcount = 0; skip = 0;
295 printf ("Usage: %s\n\n%s", *__libc_argv, _help);
296 exit (arg == 'h' ? EXIT_SUCCESS : EXIT_FAILURE);
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)
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);
314 // Check roottask command line for symbols and lines options
316 if (strstr (_modules[2], " -symbols"))
318 _modules[3] = symbols_file;
321 if (strstr (_modules[2], " -lines"))
323 _modules[4] = lines_file;
326 if (strstr (_modules[2], " -configfile"))
328 _modules[5] = roottask_config_file;
334 panic("uname: %s", strerror (errno));
337 printf ("\n\nFiasco-UX on %s %s (%s)\n",
338 uts.sysname, uts.release, uts.machine);
340 get_minimum_map_address();
343 if ((_fd = open (physmem_file, O_RDWR | O_CREAT | O_EXCL | O_TRUNC, 0700))
345 panic ("cannot create physmem: %s", strerror (errno));
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))
350 unlink (physmem_file);
351 panic ("Invalid permissions for physmem file");
354 struct statvfs stvfs;
355 if (statvfs(physmem_file, &stvfs) < 0)
358 panic("Cannot query statistics on physmem file");
361 unlink (physmem_file);
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)
371 if (memsize > 1 << 30)
375 if (memsize + _fb_size + _input_size > stvfs.f_bavail * stvfs.f_bsize)
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);
381 // The framebuffer starts beyond the physical memory
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));
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));
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);
402 mbi->flags = Multiboot_info::Memory | Multiboot_info::Cmdline |
403 Multiboot_info::Mods;
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);
411 // Copying of modules starts at the top, right below the kmem reserved area
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);
420 // Load/copy the modules
421 for (m = _modules; m < _modules + modcount; m++)
423 unsigned long start, end;
429 // Cut off between module name and command line
430 if ((cmd = strchr (const_cast<char *>(*m), ' ')))
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);
447 printf ("%s: %s\n", error, *m);
451 // Reattach command line
455 mbm->string = str - (char *) mbi + mbi_phys();
457 // Copy module name with path and command line
458 str = stpcpy (str, *m) + 1;
460 // sigma0: save memory region
461 if (m == _modules + 1)
463 _sigma0_start = start;
467 // roottask: save memory region and pass in the extra command line
468 if (m == _modules + 2)
473 str = stpcpy (str, buffer) + 1;
481 puts ("\nBootstrapping...");
486 Boot_info::get_minimum_map_address()
488 FILE *f = fopen("/proc/sys/vm/mmap_min_addr", "r");
492 int r = fscanf(f, "%ld", &_min_mappable_address);
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
500 _min_mappable_address = 0x10000;
502 _min_mappable_address
503 = (_min_mappable_address + (Config::PAGE_SIZE - 1)) & Config::PAGE_MASK;
508 Boot_info::find_x86_tls_base()
510 // the base is different on 32 and 64 bit hosts, so we need to find the
512 // be very pessimistic and scan a larger range
514 for (unsigned nr = 0; nr < 40; ++nr)
517 int r = Emulation::get_thread_area(&desc, nr);
519 panic("get_thread_area not available");
522 Emulation::set_host_tls_base(nr);
527 panic("finding TLS base did not work");
532 Boot_info::reset_checksum_ro()
535 IMPLEMENT inline NEEDS ["mem_layout.h"]
537 Boot_info::mbi_phys()
539 return Mem_layout::Multiboot_frame;
542 IMPLEMENT inline NEEDS ["mem_layout.h"]
544 Boot_info::mbi_virt()
546 return reinterpret_cast<Multiboot_info * const>
547 (Mem_layout::Physmem + mbi_phys());
551 Multiboot_vbe_controller *
554 return reinterpret_cast<Multiboot_vbe_controller *>(_mbi_vbe);
559 Boot_info::mbi_size()
561 return (unsigned long)mbi_vbe()
562 + sizeof (Multiboot_vbe_controller) + sizeof (Multiboot_vbe_mode)
563 - (unsigned long)mbi_virt();
583 Boot_info::irq0_disabled()
584 { return _irq0_disabled; }
588 Boot_info::input_start()
589 { return fb_virt() + fb_size(); }
593 Boot_info::input_size()
594 { return _input_size; }
613 Boot_info::fb_width()
614 { return _fb_width; }
618 Boot_info::fb_height()
619 { return _fb_height; }
623 Boot_info::fb_depth()
624 { return _fb_depth; }
628 Boot_info::fb_program()
629 { return _fb_program; }
633 Boot_info::net_program()
634 { return _net_program; }
643 Boot_info::irq0_path()
644 { return _irq0_program; }
648 Boot_info::emulate_clisti()
649 { return _emulate_clisti; }
653 Boot_info::sigma0_start()
654 { return _sigma0_start; }
658 Boot_info::sigma0_end()
659 { return _sigma0_end; }
663 Boot_info::root_start()
664 { return _root_start; }
668 Boot_info::root_end()
669 { return _root_end; }
673 Boot_info::min_mappable_address()
674 { return _min_mappable_address; }
678 Boot_info::get_checksum_ro(void)
683 Boot_info::get_checksum_rw(void)
689 Boot_info::set_wait()
690 { Koptions::o()->flags |= Koptions::F_wait; }
694 Boot_info::kmemsize(unsigned int k)
695 { Koptions::o()->kmemsize = k; }
699 Boot_info::set_jdb_cmd(const char *j)
701 strncpy(Koptions::o()->jdb_cmd, j, sizeof(Koptions::o()->jdb_cmd));
702 Koptions::o()->jdb_cmd[sizeof(Koptions::o()->jdb_cmd) - 1] = 0;