1/* 2 * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) 3 * Licensed under the GPL 4 */ 5 6#include "linux/kernel.h" 7#include "linux/sched.h" 8#include "linux/notifier.h" 9#include "linux/mm.h" 10#include "linux/types.h" 11#include "linux/tty.h" 12#include "linux/init.h" 13#include "linux/bootmem.h" 14#include "linux/spinlock.h" 15#include "linux/utsname.h" 16#include "linux/sysrq.h" 17#include "linux/seq_file.h" 18#include "linux/delay.h" 19#include "linux/module.h" 20#include "linux/utsname.h" 21#include "asm/page.h" 22#include "asm/pgtable.h" 23#include "asm/ptrace.h" 24#include "asm/elf.h" 25#include "asm/user.h" 26#include "asm/setup.h" 27#include "ubd_user.h" 28#include "asm/current.h" 29#include "kern_util.h" 30#include "as-layout.h" 31#include "arch.h" 32#include "kern.h" 33#include "mem_user.h" 34#include "mem.h" 35#include "initrd.h" 36#include "init.h" 37#include "os.h" 38#include "choose-mode.h" 39#include "mode_kern.h" 40#include "mode.h" 41#ifdef UML_CONFIG_MODE_SKAS 42#include "skas.h" 43#endif 44 45#define DEFAULT_COMMAND_LINE "root=98:0" 46 47/* Changed in add_arg and setup_arch, which run before SMP is started */ 48static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 }; 49 50static void __init add_arg(char *arg) 51{ 52 if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) { 53 printf("add_arg: Too many command line arguments!\n"); 54 exit(1); 55 } 56 if(strlen(command_line) > 0) 57 strcat(command_line, " "); 58 strcat(command_line, arg); 59} 60 61struct cpuinfo_um boot_cpu_data = { 62 .loops_per_jiffy = 0, 63 .ipi_pipe = { -1, -1 } 64}; 65 66unsigned long thread_saved_pc(struct task_struct *task) 67{ 68 return os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, 69 task)); 70} 71 72/* Changed in setup_arch, which is called in early boot */ 73static char host_info[(__NEW_UTS_LEN + 1) * 5]; 74 75static int show_cpuinfo(struct seq_file *m, void *v) 76{ 77 int index = 0; 78 79#ifdef CONFIG_SMP 80 index = (struct cpuinfo_um *) v - cpu_data; 81 if (!cpu_online(index)) 82 return 0; 83#endif 84 85 seq_printf(m, "processor\t: %d\n", index); 86 seq_printf(m, "vendor_id\t: User Mode Linux\n"); 87 seq_printf(m, "model name\t: UML\n"); 88 seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas")); 89 seq_printf(m, "host\t\t: %s\n", host_info); 90 seq_printf(m, "bogomips\t: %lu.%02lu\n\n", 91 loops_per_jiffy/(500000/HZ), 92 (loops_per_jiffy/(5000/HZ)) % 100); 93 94 return 0; 95} 96 97static void *c_start(struct seq_file *m, loff_t *pos) 98{ 99 return *pos < NR_CPUS ? cpu_data + *pos : NULL; 100} 101 102static void *c_next(struct seq_file *m, void *v, loff_t *pos) 103{ 104 ++*pos; 105 return c_start(m, pos); 106} 107 108static void c_stop(struct seq_file *m, void *v) 109{ 110} 111 112const struct seq_operations cpuinfo_op = { 113 .start = c_start, 114 .next = c_next, 115 .stop = c_stop, 116 .show = show_cpuinfo, 117}; 118 119/* Set in linux_main */ 120unsigned long host_task_size; 121unsigned long task_size; 122unsigned long uml_physmem; 123unsigned long uml_reserved; /* Also modified in mem_init */ 124unsigned long start_vm; 125unsigned long end_vm; 126 127/* Set in uml_ncpus_setup */ 128int ncpus = 1; 129 130#ifdef CONFIG_CMDLINE_ON_HOST 131/* Pointer set in linux_main, the array itself is private to each thread, 132 * and changed at address space creation time so this poses no concurrency 133 * problems. 134 */ 135static char *argv1_begin = NULL; 136static char *argv1_end = NULL; 137#endif 138 139/* Set in early boot */ 140static int have_root __initdata = 0; 141 142/* Set in uml_mem_setup and modified in linux_main */ 143long long physmem_size = 32 * 1024 * 1024; 144 145void set_cmdline(char *cmd) 146{ 147#ifdef CONFIG_CMDLINE_ON_HOST 148 char *umid, *ptr; 149 150 if(CHOOSE_MODE(honeypot, 0)) return; 151 152 umid = get_umid(); 153 if(*umid != '\0'){ 154 snprintf(argv1_begin, 155 (argv1_end - argv1_begin) * sizeof(*ptr), 156 "(%s) ", umid); 157 ptr = &argv1_begin[strlen(argv1_begin)]; 158 } 159 else ptr = argv1_begin; 160 161 snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd); 162 memset(argv1_begin + strlen(argv1_begin), '\0', 163 argv1_end - argv1_begin - strlen(argv1_begin)); 164#endif 165} 166 167static char *usage_string = 168"User Mode Linux v%s\n" 169" available at http://user-mode-linux.sourceforge.net/\n\n"; 170 171static int __init uml_version_setup(char *line, int *add) 172{ 173 printf("%s\n", init_utsname()->release); 174 exit(0); 175 176 return 0; 177} 178 179__uml_setup("--version", uml_version_setup, 180"--version\n" 181" Prints the version number of the kernel.\n\n" 182); 183 184static int __init uml_root_setup(char *line, int *add) 185{ 186 have_root = 1; 187 return 0; 188} 189 190__uml_setup("root=", uml_root_setup, 191"root=<file containing the root fs>\n" 192" This is actually used by the generic kernel in exactly the same\n" 193" way as in any other kernel. If you configure a number of block\n" 194" devices and want to boot off something other than ubd0, you \n" 195" would use something like:\n" 196" root=/dev/ubd5\n\n" 197); 198 199#ifndef CONFIG_MODE_TT 200 201static int __init no_skas_debug_setup(char *line, int *add) 202{ 203 printf("'debug' is not necessary to gdb UML in skas mode - run \n"); 204 printf("'gdb linux' and disable CONFIG_CMDLINE_ON_HOST if gdb \n"); 205 printf("doesn't work as expected\n"); 206 207 return 0; 208} 209 210__uml_setup("debug", no_skas_debug_setup, 211"debug\n" 212" this flag is not needed to run gdb on UML in skas mode\n\n" 213); 214 215#endif 216 217#ifdef CONFIG_SMP 218static int __init uml_ncpus_setup(char *line, int *add) 219{ 220 if (!sscanf(line, "%d", &ncpus)) { 221 printf("Couldn't parse [%s]\n", line); 222 return -1; 223 } 224 225 return 0; 226} 227 228__uml_setup("ncpus=", uml_ncpus_setup, 229"ncpus=<# of desired CPUs>\n" 230" This tells an SMP kernel how many virtual processors to start.\n\n" 231); 232#endif 233 234static int force_tt = 0; 235 236#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS) 237#define DEFAULT_TT 0 238 239static int __init mode_tt_setup(char *line, int *add) 240{ 241 force_tt = 1; 242 return 0; 243} 244 245#else 246#ifdef CONFIG_MODE_SKAS 247 248#define DEFAULT_TT 0 249 250static int __init mode_tt_setup(char *line, int *add) 251{ 252 printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n"); 253 return 0; 254} 255 256#else 257#ifdef CONFIG_MODE_TT 258 259#define DEFAULT_TT 1 260 261static int __init mode_tt_setup(char *line, int *add) 262{ 263 printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n"); 264 return 0; 265} 266 267#endif 268#endif 269#endif 270 271__uml_setup("mode=tt", mode_tt_setup, 272"mode=tt\n" 273" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n" 274" forces UML to run in tt (tracing thread) mode. It is not the default\n" 275" because it's slower and less secure than skas mode.\n\n" 276); 277 278int mode_tt = DEFAULT_TT; 279 280static int __init Usage(char *line, int *add) 281{ 282 const char **p; 283 284 printf(usage_string, init_utsname()->release); 285 p = &__uml_help_start; 286 while (p < &__uml_help_end) { 287 printf("%s", *p); 288 p++; 289 } 290 exit(0); 291 return 0; 292} 293 294__uml_setup("--help", Usage, 295"--help\n" 296" Prints this message.\n\n" 297); 298 299static int __init uml_checksetup(char *line, int *add) 300{ 301 struct uml_param *p; 302 303 p = &__uml_setup_start; 304 while(p < &__uml_setup_end) { 305 int n; 306 307 n = strlen(p->str); 308 if(!strncmp(line, p->str, n)){ 309 if (p->setup_func(line + n, add)) return 1; 310 } 311 p++; 312 } 313 return 0; 314} 315 316static void __init uml_postsetup(void) 317{ 318 initcall_t *p; 319 320 p = &__uml_postsetup_start; 321 while(p < &__uml_postsetup_end){ 322 (*p)(); 323 p++; 324 } 325 return; 326} 327 328/* Set during early boot */ 329unsigned long brk_start; 330unsigned long end_iomem; 331EXPORT_SYMBOL(end_iomem); 332 333#define MIN_VMALLOC (32 * 1024 * 1024) 334 335extern char __binary_start; 336 337int __init linux_main(int argc, char **argv) 338{ 339 unsigned long avail, diff; 340 unsigned long virtmem_size, max_physmem; 341 unsigned int i, add; 342 char * mode; 343 344 for (i = 1; i < argc; i++){ 345 if((i == 1) && (argv[i][0] == ' ')) continue; 346 add = 1; 347 uml_checksetup(argv[i], &add); 348 if (add) 349 add_arg(argv[i]); 350 } 351 if(have_root == 0) 352 add_arg(DEFAULT_COMMAND_LINE); 353 354 os_early_checks(); 355 if (force_tt) 356 clear_can_do_skas(); 357 mode_tt = force_tt ? 1 : !can_do_skas(); 358#ifndef CONFIG_MODE_TT 359 if (mode_tt) { 360 /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So, 361 * can_do_skas() returned 0, and the message is correct. */ 362 printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n"); 363 exit(1); 364 } 365#endif 366 367#ifndef CONFIG_MODE_SKAS 368 mode = "TT"; 369#else 370 /* Show to the user the result of selection */ 371 if (mode_tt) 372 mode = "TT"; 373 else if (proc_mm && ptrace_faultinfo) 374 mode = "SKAS3"; 375 else 376 mode = "SKAS0"; 377#endif 378 379 printf("UML running in %s mode\n", mode); 380 381 host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt, 382 set_task_sizes_skas, &task_size); 383 384 /* 385 * Setting up handlers to 'sig_info' struct 386 */ 387 os_fill_handlinfo(handlinfo_kern); 388 389 brk_start = (unsigned long) sbrk(0); 390 CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); 391 /* Increase physical memory size for exec-shield users 392 so they actually get what they asked for. This should 393 add zero for non-exec shield users */ 394 395 diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); 396 if(diff > 1024 * 1024){ 397 printf("Adding %ld bytes to physical memory to account for " 398 "exec-shield gap\n", diff); 399 physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); 400 } 401 402 uml_physmem = (unsigned long) &__binary_start & PAGE_MASK; 403 404 /* Reserve up to 4M after the current brk */ 405 uml_reserved = ROUND_4M(brk_start) + (1 << 22); 406 407 setup_machinename(init_utsname()->machine); 408 409#ifdef CONFIG_CMDLINE_ON_HOST 410 argv1_begin = argv[1]; 411 argv1_end = &argv[1][strlen(argv[1])]; 412#endif 413 414 highmem = 0; 415 iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; 416 max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC; 417 418 /* Zones have to begin on a 1 << MAX_ORDER page boundary, 419 * so this makes sure that's true for highmem 420 */ 421 max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1); 422 if(physmem_size + iomem_size > max_physmem){ 423 highmem = physmem_size + iomem_size - max_physmem; 424 physmem_size -= highmem; 425#ifndef CONFIG_HIGHMEM 426 highmem = 0; 427 printf("CONFIG_HIGHMEM not enabled - physical memory shrunk " 428 "to %Lu bytes\n", physmem_size); 429#endif 430 } 431 432 high_physmem = uml_physmem + physmem_size; 433 end_iomem = high_physmem + iomem_size; 434 high_memory = (void *) end_iomem; 435 436 start_vm = VMALLOC_START; 437 438 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); 439 if(init_maps(physmem_size, iomem_size, highmem)){ 440 printf("Failed to allocate mem_map for %Lu bytes of physical " 441 "memory and %Lu bytes of highmem\n", physmem_size, 442 highmem); 443 exit(1); 444 } 445 446 virtmem_size = physmem_size; 447 avail = get_kmem_end() - start_vm; 448 if(physmem_size > avail) virtmem_size = avail; 449 end_vm = start_vm + virtmem_size; 450 451 if(virtmem_size < physmem_size) 452 printf("Kernel virtual memory size shrunk to %lu bytes\n", 453 virtmem_size); 454 455 uml_postsetup(); 456 457 stack_protections((unsigned long) &init_thread_info); 458 os_flush_stdout(); 459 460 return CHOOSE_MODE(start_uml_tt(), start_uml_skas()); 461} 462 463extern int uml_exitcode; 464 465static int panic_exit(struct notifier_block *self, unsigned long unused1, 466 void *unused2) 467{ 468 bust_spinlocks(1); 469 show_regs(&(current->thread.regs)); 470 bust_spinlocks(0); 471 uml_exitcode = 1; 472 os_dump_core(); 473 return 0; 474} 475 476static struct notifier_block panic_exit_notifier = { 477 .notifier_call = panic_exit, 478 .next = NULL, 479 .priority = 0 480}; 481 482void __init setup_arch(char **cmdline_p) 483{ 484 atomic_notifier_chain_register(&panic_notifier_list, 485 &panic_exit_notifier); 486 paging_init(); 487 strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); 488 *cmdline_p = command_line; 489 setup_hostinfo(host_info, sizeof host_info); 490} 491 492void __init check_bugs(void) 493{ 494 arch_check_bugs(); 495 os_check_bugs(); 496} 497 498void apply_alternatives(struct alt_instr *start, struct alt_instr *end) 499{ 500} 501 502#ifdef CONFIG_SMP 503void alternatives_smp_module_add(struct module *mod, char *name, 504 void *locks, void *locks_end, 505 void *text, void *text_end) 506{ 507} 508 509void alternatives_smp_module_del(struct module *mod) 510{ 511} 512#endif 513