1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 */ 5 6#include <linux/cpu.h> 7#include <linux/delay.h> 8#include <linux/init.h> 9#include <linux/mm.h> 10#include <linux/ctype.h> 11#include <linux/module.h> 12#include <linux/panic_notifier.h> 13#include <linux/seq_file.h> 14#include <linux/string.h> 15#include <linux/utsname.h> 16#include <linux/sched.h> 17#include <linux/sched/task.h> 18#include <linux/kmsg_dump.h> 19#include <linux/suspend.h> 20#include <linux/random.h> 21 22#include <asm/processor.h> 23#include <asm/cpufeature.h> 24#include <asm/sections.h> 25#include <asm/setup.h> 26#include <as-layout.h> 27#include <arch.h> 28#include <init.h> 29#include <kern.h> 30#include <kern_util.h> 31#include <mem_user.h> 32#include <os.h> 33 34#include "um_arch.h" 35 36#define DEFAULT_COMMAND_LINE_ROOT "root=98:0" 37#define DEFAULT_COMMAND_LINE_CONSOLE "console=tty0" 38 39/* Changed in add_arg and setup_arch, which run before SMP is started */ 40static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 }; 41 42static void __init add_arg(char *arg) 43{ 44 if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) { 45 os_warn("add_arg: Too many command line arguments!\n"); 46 exit(1); 47 } 48 if (strlen(command_line) > 0) 49 strcat(command_line, " "); 50 strcat(command_line, arg); 51} 52 53/* 54 * These fields are initialized at boot time and not changed. 55 * XXX This structure is used only in the non-SMP case. Maybe this 56 * should be moved to smp.c. 57 */ 58struct cpuinfo_um boot_cpu_data = { 59 .loops_per_jiffy = 0, 60 .ipi_pipe = { -1, -1 }, 61 .cache_alignment = L1_CACHE_BYTES, 62 .x86_capability = { 0 } 63}; 64 65EXPORT_SYMBOL(boot_cpu_data); 66 67union thread_union cpu0_irqstack 68 __section(".data..init_irqstack") = 69 { .thread_info = INIT_THREAD_INFO(init_task) }; 70 71/* Changed in setup_arch, which is called in early boot */ 72static char host_info[(__NEW_UTS_LEN + 1) * 5]; 73 74static int show_cpuinfo(struct seq_file *m, void *v) 75{ 76 int i = 0; 77 78 seq_printf(m, "processor\t: %d\n", i); 79 seq_printf(m, "vendor_id\t: User Mode Linux\n"); 80 seq_printf(m, "model name\t: UML\n"); 81 seq_printf(m, "mode\t\t: skas\n"); 82 seq_printf(m, "host\t\t: %s\n", host_info); 83 seq_printf(m, "fpu\t\t: %s\n", cpu_has(&boot_cpu_data, X86_FEATURE_FPU) ? "yes" : "no"); 84 seq_printf(m, "flags\t\t:"); 85 for (i = 0; i < 32*NCAPINTS; i++) 86 if (cpu_has(&boot_cpu_data, i) && (x86_cap_flags[i] != NULL)) 87 seq_printf(m, " %s", x86_cap_flags[i]); 88 seq_printf(m, "\n"); 89 seq_printf(m, "cache_alignment\t: %d\n", boot_cpu_data.cache_alignment); 90 seq_printf(m, "bogomips\t: %lu.%02lu\n", 91 loops_per_jiffy/(500000/HZ), 92 (loops_per_jiffy/(5000/HZ)) % 100); 93 94 95 return 0; 96} 97 98static void *c_start(struct seq_file *m, loff_t *pos) 99{ 100 return *pos < nr_cpu_ids ? &boot_cpu_data + *pos : NULL; 101} 102 103static void *c_next(struct seq_file *m, void *v, loff_t *pos) 104{ 105 ++*pos; 106 return c_start(m, pos); 107} 108 109static void c_stop(struct seq_file *m, void *v) 110{ 111} 112 113const struct seq_operations cpuinfo_op = { 114 .start = c_start, 115 .next = c_next, 116 .stop = c_stop, 117 .show = show_cpuinfo, 118}; 119 120/* Set in linux_main */ 121unsigned long uml_physmem; 122EXPORT_SYMBOL(uml_physmem); 123 124unsigned long uml_reserved; /* Also modified in mem_init */ 125unsigned long start_vm; 126unsigned long end_vm; 127 128/* Set in uml_ncpus_setup */ 129int ncpus = 1; 130 131/* Set in early boot */ 132static int have_root __initdata; 133static int have_console __initdata; 134 135/* Set in uml_mem_setup and modified in linux_main */ 136long long physmem_size = 64 * 1024 * 1024; 137EXPORT_SYMBOL(physmem_size); 138 139static const char *usage_string = 140"User Mode Linux v%s\n" 141" available at http://user-mode-linux.sourceforge.net/\n\n"; 142 143static int __init uml_version_setup(char *line, int *add) 144{ 145 /* Explicitly use printf() to show version in stdout */ 146 printf("%s\n", init_utsname()->release); 147 exit(0); 148 149 return 0; 150} 151 152__uml_setup("--version", uml_version_setup, 153"--version\n" 154" Prints the version number of the kernel.\n\n" 155); 156 157static int __init uml_root_setup(char *line, int *add) 158{ 159 have_root = 1; 160 return 0; 161} 162 163__uml_setup("root=", uml_root_setup, 164"root=<file containing the root fs>\n" 165" This is actually used by the generic kernel in exactly the same\n" 166" way as in any other kernel. If you configure a number of block\n" 167" devices and want to boot off something other than ubd0, you \n" 168" would use something like:\n" 169" root=/dev/ubd5\n\n" 170); 171 172static int __init no_skas_debug_setup(char *line, int *add) 173{ 174 os_warn("'debug' is not necessary to gdb UML in skas mode - run\n"); 175 os_warn("'gdb linux'\n"); 176 177 return 0; 178} 179 180__uml_setup("debug", no_skas_debug_setup, 181"debug\n" 182" this flag is not needed to run gdb on UML in skas mode\n\n" 183); 184 185static int __init uml_console_setup(char *line, int *add) 186{ 187 have_console = 1; 188 return 0; 189} 190 191__uml_setup("console=", uml_console_setup, 192"console=<preferred console>\n" 193" Specify the preferred console output driver\n\n" 194); 195 196static int __init Usage(char *line, int *add) 197{ 198 const char **p; 199 200 printf(usage_string, init_utsname()->release); 201 p = &__uml_help_start; 202 /* Explicitly use printf() to show help in stdout */ 203 while (p < &__uml_help_end) { 204 printf("%s", *p); 205 p++; 206 } 207 exit(0); 208 return 0; 209} 210 211__uml_setup("--help", Usage, 212"--help\n" 213" Prints this message.\n\n" 214); 215 216static void __init uml_checksetup(char *line, int *add) 217{ 218 struct uml_param *p; 219 220 p = &__uml_setup_start; 221 while (p < &__uml_setup_end) { 222 size_t n; 223 224 n = strlen(p->str); 225 if (!strncmp(line, p->str, n) && p->setup_func(line + n, add)) 226 return; 227 p++; 228 } 229} 230 231static void __init uml_postsetup(void) 232{ 233 initcall_t *p; 234 235 p = &__uml_postsetup_start; 236 while (p < &__uml_postsetup_end) { 237 (*p)(); 238 p++; 239 } 240 return; 241} 242 243static int panic_exit(struct notifier_block *self, unsigned long unused1, 244 void *unused2) 245{ 246 kmsg_dump(KMSG_DUMP_PANIC); 247 bust_spinlocks(1); 248 bust_spinlocks(0); 249 uml_exitcode = 1; 250 os_dump_core(); 251 252 return NOTIFY_DONE; 253} 254 255static struct notifier_block panic_exit_notifier = { 256 .notifier_call = panic_exit, 257 .priority = INT_MAX - 1, /* run as 2nd notifier, won't return */ 258}; 259 260void uml_finishsetup(void) 261{ 262 atomic_notifier_chain_register(&panic_notifier_list, 263 &panic_exit_notifier); 264 265 uml_postsetup(); 266 267 new_thread_handler(); 268} 269 270/* Set during early boot */ 271unsigned long stub_start; 272unsigned long task_size; 273EXPORT_SYMBOL(task_size); 274 275unsigned long host_task_size; 276 277unsigned long brk_start; 278unsigned long end_iomem; 279EXPORT_SYMBOL(end_iomem); 280 281#define MIN_VMALLOC (32 * 1024 * 1024) 282 283static void parse_host_cpu_flags(char *line) 284{ 285 int i; 286 for (i = 0; i < 32*NCAPINTS; i++) { 287 if ((x86_cap_flags[i] != NULL) && strstr(line, x86_cap_flags[i])) 288 set_cpu_cap(&boot_cpu_data, i); 289 } 290} 291static void parse_cache_line(char *line) 292{ 293 long res; 294 char *to_parse = strstr(line, ":"); 295 if (to_parse) { 296 to_parse++; 297 while (*to_parse != 0 && isspace(*to_parse)) { 298 to_parse++; 299 } 300 if (kstrtoul(to_parse, 10, &res) == 0 && is_power_of_2(res)) 301 boot_cpu_data.cache_alignment = res; 302 else 303 boot_cpu_data.cache_alignment = L1_CACHE_BYTES; 304 } 305} 306 307int __init linux_main(int argc, char **argv) 308{ 309 unsigned long avail, diff; 310 unsigned long virtmem_size, max_physmem; 311 unsigned long stack; 312 unsigned int i; 313 int add; 314 315 for (i = 1; i < argc; i++) { 316 if ((i == 1) && (argv[i][0] == ' ')) 317 continue; 318 add = 1; 319 uml_checksetup(argv[i], &add); 320 if (add) 321 add_arg(argv[i]); 322 } 323 if (have_root == 0) 324 add_arg(DEFAULT_COMMAND_LINE_ROOT); 325 326 if (have_console == 0) 327 add_arg(DEFAULT_COMMAND_LINE_CONSOLE); 328 329 host_task_size = os_get_top_address(); 330 /* reserve a few pages for the stubs (taking care of data alignment) */ 331 /* align the data portion */ 332 BUILD_BUG_ON(!is_power_of_2(STUB_DATA_PAGES)); 333 stub_start = (host_task_size - 1) & ~(STUB_DATA_PAGES * PAGE_SIZE - 1); 334 /* another page for the code portion */ 335 stub_start -= PAGE_SIZE; 336 host_task_size = stub_start; 337 338 /* 339 * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps 340 * out 341 */ 342 task_size = host_task_size & PGDIR_MASK; 343 344 /* OS sanity checks that need to happen before the kernel runs */ 345 os_early_checks(); 346 347 get_host_cpu_features(parse_host_cpu_flags, parse_cache_line); 348 349 brk_start = (unsigned long) sbrk(0); 350 351 /* 352 * Increase physical memory size for exec-shield users 353 * so they actually get what they asked for. This should 354 * add zero for non-exec shield users 355 */ 356 357 diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); 358 if (diff > 1024 * 1024) { 359 os_info("Adding %ld bytes to physical memory to account for " 360 "exec-shield gap\n", diff); 361 physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); 362 } 363 364 uml_physmem = (unsigned long) __binary_start & PAGE_MASK; 365 366 /* Reserve up to 4M after the current brk */ 367 uml_reserved = ROUND_4M(brk_start) + (1 << 22); 368 369 setup_machinename(init_utsname()->machine); 370 371 highmem = 0; 372 iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; 373 max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC; 374 375 /* 376 * Zones have to begin on a 1 << MAX_PAGE_ORDER page boundary, 377 * so this makes sure that's true for highmem 378 */ 379 max_physmem &= ~((1 << (PAGE_SHIFT + MAX_PAGE_ORDER)) - 1); 380 if (physmem_size + iomem_size > max_physmem) { 381 highmem = physmem_size + iomem_size - max_physmem; 382 physmem_size -= highmem; 383 } 384 385 high_physmem = uml_physmem + physmem_size; 386 end_iomem = high_physmem + iomem_size; 387 high_memory = (void *) end_iomem; 388 389 start_vm = VMALLOC_START; 390 391 virtmem_size = physmem_size; 392 stack = (unsigned long) argv; 393 stack &= ~(1024 * 1024 - 1); 394 avail = stack - start_vm; 395 if (physmem_size > avail) 396 virtmem_size = avail; 397 end_vm = start_vm + virtmem_size; 398 399 if (virtmem_size < physmem_size) 400 os_info("Kernel virtual memory size shrunk to %lu bytes\n", 401 virtmem_size); 402 403 os_flush_stdout(); 404 405 return start_uml(); 406} 407 408int __init __weak read_initrd(void) 409{ 410 return 0; 411} 412 413void __init setup_arch(char **cmdline_p) 414{ 415 u8 rng_seed[32]; 416 417 stack_protections((unsigned long) &init_thread_info); 418 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); 419 mem_total_pages(physmem_size, iomem_size, highmem); 420 uml_dtb_init(); 421 read_initrd(); 422 423 paging_init(); 424 strscpy(boot_command_line, command_line, COMMAND_LINE_SIZE); 425 *cmdline_p = command_line; 426 setup_hostinfo(host_info, sizeof host_info); 427 428 if (os_getrandom(rng_seed, sizeof(rng_seed), 0) == sizeof(rng_seed)) { 429 add_bootloader_randomness(rng_seed, sizeof(rng_seed)); 430 memzero_explicit(rng_seed, sizeof(rng_seed)); 431 } 432} 433 434void __init arch_cpu_finalize_init(void) 435{ 436 arch_check_bugs(); 437 os_check_bugs(); 438} 439 440void apply_seal_endbr(s32 *start, s32 *end) 441{ 442} 443 444void apply_retpolines(s32 *start, s32 *end) 445{ 446} 447 448void apply_returns(s32 *start, s32 *end) 449{ 450} 451 452void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, 453 s32 *start_cfi, s32 *end_cfi) 454{ 455} 456 457void apply_alternatives(struct alt_instr *start, struct alt_instr *end) 458{ 459} 460 461void *text_poke(void *addr, const void *opcode, size_t len) 462{ 463 /* 464 * In UML, the only reference to this function is in 465 * apply_relocate_add(), which shouldn't ever actually call this 466 * because UML doesn't have live patching. 467 */ 468 WARN_ON(1); 469 470 return memcpy(addr, opcode, len); 471} 472 473void text_poke_sync(void) 474{ 475} 476 477void uml_pm_wake(void) 478{ 479 pm_system_wakeup(); 480} 481 482#ifdef CONFIG_PM_SLEEP 483static int um_suspend_valid(suspend_state_t state) 484{ 485 return state == PM_SUSPEND_MEM; 486} 487 488static int um_suspend_prepare(void) 489{ 490 um_irqs_suspend(); 491 return 0; 492} 493 494static int um_suspend_enter(suspend_state_t state) 495{ 496 if (WARN_ON(state != PM_SUSPEND_MEM)) 497 return -EINVAL; 498 499 /* 500 * This is identical to the idle sleep, but we've just 501 * (during suspend) turned off all interrupt sources 502 * except for the ones we want, so now we can only wake 503 * up on something we actually want to wake up on. All 504 * timing has also been suspended. 505 */ 506 um_idle_sleep(); 507 return 0; 508} 509 510static void um_suspend_finish(void) 511{ 512 um_irqs_resume(); 513} 514 515const struct platform_suspend_ops um_suspend_ops = { 516 .valid = um_suspend_valid, 517 .prepare = um_suspend_prepare, 518 .enter = um_suspend_enter, 519 .finish = um_suspend_finish, 520}; 521 522static int init_pm_wake_signal(void) 523{ 524 /* 525 * In external time-travel mode we can't use signals to wake up 526 * since that would mess with the scheduling. We'll have to do 527 * some additional work to support wakeup on virtio devices or 528 * similar, perhaps implementing a fake RTC controller that can 529 * trigger wakeup (and request the appropriate scheduling from 530 * the external scheduler when going to suspend.) 531 */ 532 if (time_travel_mode != TT_MODE_EXTERNAL) 533 register_pm_wake_signal(); 534 535 suspend_set_ops(&um_suspend_ops); 536 537 return 0; 538} 539 540late_initcall(init_pm_wake_signal); 541#endif 542