10d1fb0a4SAlex Dewar // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 3ba180fd4SJeff Dike * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 41da177e4SLinus Torvalds */ 51da177e4SLinus Torvalds 6c5d4bb17SJeff Dike #include <linux/delay.h> 7c5d4bb17SJeff Dike #include <linux/init.h> 8c5d4bb17SJeff Dike #include <linux/mm.h> 9d8fb32f4SAnton Ivanov #include <linux/ctype.h> 10c5d4bb17SJeff Dike #include <linux/module.h> 11f39650deSAndy Shevchenko #include <linux/panic_notifier.h> 12c5d4bb17SJeff Dike #include <linux/seq_file.h> 13c5d4bb17SJeff Dike #include <linux/string.h> 14c5d4bb17SJeff Dike #include <linux/utsname.h> 155b408241SThomas Gleixner #include <linux/sched.h> 169164bb4aSIngo Molnar #include <linux/sched/task.h> 1704a41849SThomas Meyer #include <linux/kmsg_dump.h> 1892dcd3d3SJohannes Berg #include <linux/suspend.h> 190b9ba613SJason A. Donenfeld #include <linux/random.h> 209164bb4aSIngo Molnar 21c5d4bb17SJeff Dike #include <asm/processor.h> 22d8fb32f4SAnton Ivanov #include <asm/cpufeature.h> 2333a7d429SGeert Uytterhoeven #include <asm/sections.h> 24c5d4bb17SJeff Dike #include <asm/setup.h> 2537185b33SAl Viro #include <as-layout.h> 2637185b33SAl Viro #include <arch.h> 2737185b33SAl Viro #include <init.h> 2837185b33SAl Viro #include <kern.h> 2937185b33SAl Viro #include <kern_util.h> 3037185b33SAl Viro #include <mem_user.h> 3137185b33SAl Viro #include <os.h> 321da177e4SLinus Torvalds 33b31297f0SVincent Whitchurch #include "um_arch.h" 34b31297f0SVincent Whitchurch 35d7ffac33SThomas Meyer #define DEFAULT_COMMAND_LINE_ROOT "root=98:0" 36d7ffac33SThomas Meyer #define DEFAULT_COMMAND_LINE_CONSOLE "console=tty" 371da177e4SLinus Torvalds 381d1497e1SJeff Dike /* Changed in add_arg and setup_arch, which run before SMP is started */ 397a3a06d0SAlon Bar-Lev static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 }; 401da177e4SLinus Torvalds 417a3a06d0SAlon Bar-Lev static void __init add_arg(char *arg) 421da177e4SLinus Torvalds { 431da177e4SLinus Torvalds if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) { 440936d4f3SMasami Hiramatsu os_warn("add_arg: Too many command line arguments!\n"); 451da177e4SLinus Torvalds exit(1); 461da177e4SLinus Torvalds } 471da177e4SLinus Torvalds if (strlen(command_line) > 0) 481da177e4SLinus Torvalds strcat(command_line, " "); 491da177e4SLinus Torvalds strcat(command_line, arg); 501da177e4SLinus Torvalds } 511da177e4SLinus Torvalds 521d1497e1SJeff Dike /* 531d1497e1SJeff Dike * These fields are initialized at boot time and not changed. 541d1497e1SJeff Dike * XXX This structure is used only in the non-SMP case. Maybe this 551d1497e1SJeff Dike * should be moved to smp.c. 561d1497e1SJeff Dike */ 571da177e4SLinus Torvalds struct cpuinfo_um boot_cpu_data = { 581da177e4SLinus Torvalds .loops_per_jiffy = 0, 59d8fb32f4SAnton Ivanov .ipi_pipe = { -1, -1 }, 60d8fb32f4SAnton Ivanov .cache_alignment = L1_CACHE_BYTES, 61d8fb32f4SAnton Ivanov .x86_capability = { 0 } 621da177e4SLinus Torvalds }; 631da177e4SLinus Torvalds 64d8fb32f4SAnton Ivanov EXPORT_SYMBOL(boot_cpu_data); 65d8fb32f4SAnton Ivanov 665b408241SThomas Gleixner union thread_union cpu0_irqstack 6733def849SJoe Perches __section(".data..init_irqstack") = 680500871fSDavid Howells { .thread_info = INIT_THREAD_INFO(init_task) }; 695b408241SThomas Gleixner 70b4ffb6adSJeff Dike /* Changed in setup_arch, which is called in early boot */ 71b4ffb6adSJeff Dike static char host_info[(__NEW_UTS_LEN + 1) * 5]; 72b4ffb6adSJeff Dike 731da177e4SLinus Torvalds static int show_cpuinfo(struct seq_file *m, void *v) 741da177e4SLinus Torvalds { 75d8fb32f4SAnton Ivanov int i = 0; 761da177e4SLinus Torvalds 77d8fb32f4SAnton Ivanov seq_printf(m, "processor\t: %d\n", i); 781da177e4SLinus Torvalds seq_printf(m, "vendor_id\t: User Mode Linux\n"); 791da177e4SLinus Torvalds seq_printf(m, "model name\t: UML\n"); 806aa802ceSJeff Dike seq_printf(m, "mode\t\t: skas\n"); 811da177e4SLinus Torvalds seq_printf(m, "host\t\t: %s\n", host_info); 82d8fb32f4SAnton Ivanov seq_printf(m, "fpu\t\t: %s\n", cpu_has(&boot_cpu_data, X86_FEATURE_FPU) ? "yes" : "no"); 83d8fb32f4SAnton Ivanov seq_printf(m, "flags\t\t:"); 84d8fb32f4SAnton Ivanov for (i = 0; i < 32*NCAPINTS; i++) 85d8fb32f4SAnton Ivanov if (cpu_has(&boot_cpu_data, i) && (x86_cap_flags[i] != NULL)) 86d8fb32f4SAnton Ivanov seq_printf(m, " %s", x86_cap_flags[i]); 87d8fb32f4SAnton Ivanov seq_printf(m, "\n"); 88d8fb32f4SAnton Ivanov seq_printf(m, "cache_alignment\t: %d\n", boot_cpu_data.cache_alignment); 89d8fb32f4SAnton Ivanov seq_printf(m, "bogomips\t: %lu.%02lu\n", 901da177e4SLinus Torvalds loops_per_jiffy/(500000/HZ), 911da177e4SLinus Torvalds (loops_per_jiffy/(5000/HZ)) % 100); 921da177e4SLinus Torvalds 93d8fb32f4SAnton Ivanov 94a5ed1ffaSJeff Dike return 0; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos) 981da177e4SLinus Torvalds { 9916c546e1SHuacai Chen return *pos < nr_cpu_ids ? cpu_data + *pos : NULL; 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos) 1031da177e4SLinus Torvalds { 1041da177e4SLinus Torvalds ++*pos; 1051da177e4SLinus Torvalds return c_start(m, pos); 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v) 1091da177e4SLinus Torvalds { 1101da177e4SLinus Torvalds } 1111da177e4SLinus Torvalds 1125e7672ecSJeff Dike const struct seq_operations cpuinfo_op = { 1131da177e4SLinus Torvalds .start = c_start, 1141da177e4SLinus Torvalds .next = c_next, 1151da177e4SLinus Torvalds .stop = c_stop, 1161da177e4SLinus Torvalds .show = show_cpuinfo, 1171da177e4SLinus Torvalds }; 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds /* Set in linux_main */ 1201da177e4SLinus Torvalds unsigned long uml_physmem; 12173395a00SAl Viro EXPORT_SYMBOL(uml_physmem); 12273395a00SAl Viro 1231d1497e1SJeff Dike unsigned long uml_reserved; /* Also modified in mem_init */ 1241da177e4SLinus Torvalds unsigned long start_vm; 1251da177e4SLinus Torvalds unsigned long end_vm; 1261d1497e1SJeff Dike 1271d1497e1SJeff Dike /* Set in uml_ncpus_setup */ 1281da177e4SLinus Torvalds int ncpus = 1; 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds /* Set in early boot */ 131d7ffac33SThomas Meyer static int have_root __initdata; 132d7ffac33SThomas Meyer static int have_console __initdata; 1331d1497e1SJeff Dike 1341d1497e1SJeff Dike /* Set in uml_mem_setup and modified in linux_main */ 1350d644e91SChristian Lamparter long long physmem_size = 64 * 1024 * 1024; 1365d38f324SErel Geron EXPORT_SYMBOL(physmem_size); 1371da177e4SLinus Torvalds 1383af9c5beSWANG Cong static const char *usage_string = 1391da177e4SLinus Torvalds "User Mode Linux v%s\n" 1401da177e4SLinus Torvalds " available at http://user-mode-linux.sourceforge.net/\n\n"; 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds static int __init uml_version_setup(char *line, int *add) 1431da177e4SLinus Torvalds { 1440936d4f3SMasami Hiramatsu /* Explicitly use printf() to show version in stdout */ 14596b644bdSSerge E. Hallyn printf("%s\n", init_utsname()->release); 1461da177e4SLinus Torvalds exit(0); 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds return 0; 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds __uml_setup("--version", uml_version_setup, 1521da177e4SLinus Torvalds "--version\n" 1531da177e4SLinus Torvalds " Prints the version number of the kernel.\n\n" 1541da177e4SLinus Torvalds ); 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds static int __init uml_root_setup(char *line, int *add) 1571da177e4SLinus Torvalds { 1581da177e4SLinus Torvalds have_root = 1; 1591da177e4SLinus Torvalds return 0; 1601da177e4SLinus Torvalds } 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds __uml_setup("root=", uml_root_setup, 1631da177e4SLinus Torvalds "root=<file containing the root fs>\n" 1641da177e4SLinus Torvalds " This is actually used by the generic kernel in exactly the same\n" 1651da177e4SLinus Torvalds " way as in any other kernel. If you configure a number of block\n" 1661da177e4SLinus Torvalds " devices and want to boot off something other than ubd0, you \n" 1671da177e4SLinus Torvalds " would use something like:\n" 1681da177e4SLinus Torvalds " root=/dev/ubd5\n\n" 1691da177e4SLinus Torvalds ); 1701da177e4SLinus Torvalds 171fbd55779SJeff Dike static int __init no_skas_debug_setup(char *line, int *add) 172fbd55779SJeff Dike { 1730936d4f3SMasami Hiramatsu os_warn("'debug' is not necessary to gdb UML in skas mode - run\n"); 1740936d4f3SMasami Hiramatsu os_warn("'gdb linux'\n"); 175fbd55779SJeff Dike 176fbd55779SJeff Dike return 0; 177fbd55779SJeff Dike } 178fbd55779SJeff Dike 179fbd55779SJeff Dike __uml_setup("debug", no_skas_debug_setup, 180fbd55779SJeff Dike "debug\n" 181fbd55779SJeff Dike " this flag is not needed to run gdb on UML in skas mode\n\n" 182fbd55779SJeff Dike ); 183fbd55779SJeff Dike 184d7ffac33SThomas Meyer static int __init uml_console_setup(char *line, int *add) 185d7ffac33SThomas Meyer { 186d7ffac33SThomas Meyer have_console = 1; 187d7ffac33SThomas Meyer return 0; 188d7ffac33SThomas Meyer } 189d7ffac33SThomas Meyer 190d7ffac33SThomas Meyer __uml_setup("console=", uml_console_setup, 191d7ffac33SThomas Meyer "console=<preferred console>\n" 192d7ffac33SThomas Meyer " Specify the preferred console output driver\n\n" 193d7ffac33SThomas Meyer ); 194d7ffac33SThomas Meyer 1951da177e4SLinus Torvalds static int __init Usage(char *line, int *add) 1961da177e4SLinus Torvalds { 1971da177e4SLinus Torvalds const char **p; 1981da177e4SLinus Torvalds 19996b644bdSSerge E. Hallyn printf(usage_string, init_utsname()->release); 2001da177e4SLinus Torvalds p = &__uml_help_start; 2010936d4f3SMasami Hiramatsu /* Explicitly use printf() to show help in stdout */ 2021da177e4SLinus Torvalds while (p < &__uml_help_end) { 2031da177e4SLinus Torvalds printf("%s", *p); 2041da177e4SLinus Torvalds p++; 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds exit(0); 2071da177e4SLinus Torvalds return 0; 2081da177e4SLinus Torvalds } 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds __uml_setup("--help", Usage, 2111da177e4SLinus Torvalds "--help\n" 2121da177e4SLinus Torvalds " Prints this message.\n\n" 2131da177e4SLinus Torvalds ); 2141da177e4SLinus Torvalds 2156b7e9674SKarol Swietlicki static void __init uml_checksetup(char *line, int *add) 2161da177e4SLinus Torvalds { 2171da177e4SLinus Torvalds struct uml_param *p; 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds p = &__uml_setup_start; 2201da177e4SLinus Torvalds while (p < &__uml_setup_end) { 2213af9c5beSWANG Cong size_t n; 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds n = strlen(p->str); 224ba180fd4SJeff Dike if (!strncmp(line, p->str, n) && p->setup_func(line + n, add)) 2256b7e9674SKarol Swietlicki return; 2261da177e4SLinus Torvalds p++; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds static void __init uml_postsetup(void) 2311da177e4SLinus Torvalds { 2321da177e4SLinus Torvalds initcall_t *p; 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds p = &__uml_postsetup_start; 2351da177e4SLinus Torvalds while (p < &__uml_postsetup_end) { 2361da177e4SLinus Torvalds (*p)(); 2371da177e4SLinus Torvalds p++; 2381da177e4SLinus Torvalds } 2391da177e4SLinus Torvalds return; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds 2420983a88bSJeff Dike static int panic_exit(struct notifier_block *self, unsigned long unused1, 2430983a88bSJeff Dike void *unused2) 2440983a88bSJeff Dike { 24504a41849SThomas Meyer kmsg_dump(KMSG_DUMP_PANIC); 2460983a88bSJeff Dike bust_spinlocks(1); 2470983a88bSJeff Dike bust_spinlocks(0); 2480983a88bSJeff Dike uml_exitcode = 1; 2490983a88bSJeff Dike os_dump_core(); 2500983a88bSJeff Dike return 0; 2510983a88bSJeff Dike } 2520983a88bSJeff Dike 2530983a88bSJeff Dike static struct notifier_block panic_exit_notifier = { 2540983a88bSJeff Dike .notifier_call = panic_exit, 2550983a88bSJeff Dike .next = NULL, 2560983a88bSJeff Dike .priority = 0 2570983a88bSJeff Dike }; 2580983a88bSJeff Dike 25933bbc306SThomas Meyer void uml_finishsetup(void) 26033bbc306SThomas Meyer { 26133bbc306SThomas Meyer atomic_notifier_chain_register(&panic_notifier_list, 26233bbc306SThomas Meyer &panic_exit_notifier); 26333bbc306SThomas Meyer 26433bbc306SThomas Meyer uml_postsetup(); 26533bbc306SThomas Meyer 26633bbc306SThomas Meyer new_thread_handler(); 26733bbc306SThomas Meyer } 26833bbc306SThomas Meyer 2691da177e4SLinus Torvalds /* Set during early boot */ 270bfc58e2bSJohannes Berg unsigned long stub_start; 271536788feSJeff Dike unsigned long task_size; 272536788feSJeff Dike EXPORT_SYMBOL(task_size); 273536788feSJeff Dike 274536788feSJeff Dike unsigned long host_task_size; 275536788feSJeff Dike 2761da177e4SLinus Torvalds unsigned long brk_start; 2771da177e4SLinus Torvalds unsigned long end_iomem; 2781da177e4SLinus Torvalds EXPORT_SYMBOL(end_iomem); 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds #define MIN_VMALLOC (32 * 1024 * 1024) 2811da177e4SLinus Torvalds 282d8fb32f4SAnton Ivanov static void parse_host_cpu_flags(char *line) 283d8fb32f4SAnton Ivanov { 284d8fb32f4SAnton Ivanov int i; 285d8fb32f4SAnton Ivanov for (i = 0; i < 32*NCAPINTS; i++) { 286d8fb32f4SAnton Ivanov if ((x86_cap_flags[i] != NULL) && strstr(line, x86_cap_flags[i])) 2871aee0201SWan Jiabing set_cpu_cap(&boot_cpu_data, i); 288d8fb32f4SAnton Ivanov } 289d8fb32f4SAnton Ivanov } 290d8fb32f4SAnton Ivanov static void parse_cache_line(char *line) 291d8fb32f4SAnton Ivanov { 292d8fb32f4SAnton Ivanov long res; 293d8fb32f4SAnton Ivanov char *to_parse = strstr(line, ":"); 294d8fb32f4SAnton Ivanov if (to_parse) { 295d8fb32f4SAnton Ivanov to_parse++; 296d8fb32f4SAnton Ivanov while (*to_parse != 0 && isspace(*to_parse)) { 297d8fb32f4SAnton Ivanov to_parse++; 298d8fb32f4SAnton Ivanov } 299d8fb32f4SAnton Ivanov if (kstrtoul(to_parse, 10, &res) == 0 && is_power_of_2(res)) 300d8fb32f4SAnton Ivanov boot_cpu_data.cache_alignment = res; 301d8fb32f4SAnton Ivanov else 302d8fb32f4SAnton Ivanov boot_cpu_data.cache_alignment = L1_CACHE_BYTES; 303d8fb32f4SAnton Ivanov } 304d8fb32f4SAnton Ivanov } 305d8fb32f4SAnton Ivanov 3067a3a06d0SAlon Bar-Lev int __init linux_main(int argc, char **argv) 3071da177e4SLinus Torvalds { 3081da177e4SLinus Torvalds unsigned long avail, diff; 3091da177e4SLinus Torvalds unsigned long virtmem_size, max_physmem; 31060a2988aSJeff Dike unsigned long stack; 3113af9c5beSWANG Cong unsigned int i; 3123af9c5beSWANG Cong int add; 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds for (i = 1; i < argc; i++) { 315ba180fd4SJeff Dike if ((i == 1) && (argv[i][0] == ' ')) 316ba180fd4SJeff Dike continue; 3171da177e4SLinus Torvalds add = 1; 3181da177e4SLinus Torvalds uml_checksetup(argv[i], &add); 3191da177e4SLinus Torvalds if (add) 3201da177e4SLinus Torvalds add_arg(argv[i]); 3211da177e4SLinus Torvalds } 3221da177e4SLinus Torvalds if (have_root == 0) 323d7ffac33SThomas Meyer add_arg(DEFAULT_COMMAND_LINE_ROOT); 324d7ffac33SThomas Meyer 325d7ffac33SThomas Meyer if (have_console == 0) 326d7ffac33SThomas Meyer add_arg(DEFAULT_COMMAND_LINE_CONSOLE); 3271da177e4SLinus Torvalds 32840fb16a3STom Spink host_task_size = os_get_top_address(); 329bfc58e2bSJohannes Berg /* reserve two pages for the stubs */ 330bfc58e2bSJohannes Berg host_task_size -= 2 * PAGE_SIZE; 331bfc58e2bSJohannes Berg stub_start = host_task_size; 332bfc58e2bSJohannes Berg 333536788feSJeff Dike /* 334536788feSJeff Dike * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps 335536788feSJeff Dike * out 336536788feSJeff Dike */ 337536788feSJeff Dike task_size = host_task_size & PGDIR_MASK; 338536788feSJeff Dike 339ba180fd4SJeff Dike /* OS sanity checks that need to happen before the kernel runs */ 34060d339f6SGennady Sharapov os_early_checks(); 341cb66504dSPaolo 'Blaisorblade' Giarrusso 342d8fb32f4SAnton Ivanov get_host_cpu_features(parse_host_cpu_flags, parse_cache_line); 343d8fb32f4SAnton Ivanov 3441da177e4SLinus Torvalds brk_start = (unsigned long) sbrk(0); 34577bf4400SJeff Dike 346ba180fd4SJeff Dike /* 347ba180fd4SJeff Dike * Increase physical memory size for exec-shield users 348ba180fd4SJeff Dike * so they actually get what they asked for. This should 349ba180fd4SJeff Dike * add zero for non-exec shield users 350ba180fd4SJeff Dike */ 3511da177e4SLinus Torvalds 3521da177e4SLinus Torvalds diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); 3531da177e4SLinus Torvalds if (diff > 1024 * 1024) { 354d3878bb8SMasami Hiramatsu os_info("Adding %ld bytes to physical memory to account for " 3551da177e4SLinus Torvalds "exec-shield gap\n", diff); 3561da177e4SLinus Torvalds physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); 3571da177e4SLinus Torvalds } 3581da177e4SLinus Torvalds 35905eacfd0SNicolas Iooss uml_physmem = (unsigned long) __binary_start & PAGE_MASK; 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds /* Reserve up to 4M after the current brk */ 3621da177e4SLinus Torvalds uml_reserved = ROUND_4M(brk_start) + (1 << 22); 3631da177e4SLinus Torvalds 36496b644bdSSerge E. Hallyn setup_machinename(init_utsname()->machine); 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds highmem = 0; 3671da177e4SLinus Torvalds iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; 368536788feSJeff Dike max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC; 3691da177e4SLinus Torvalds 370ba180fd4SJeff Dike /* 371ba180fd4SJeff Dike * Zones have to begin on a 1 << MAX_ORDER page boundary, 3721da177e4SLinus Torvalds * so this makes sure that's true for highmem 3731da177e4SLinus Torvalds */ 3741da177e4SLinus Torvalds max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1); 3751da177e4SLinus Torvalds if (physmem_size + iomem_size > max_physmem) { 3761da177e4SLinus Torvalds highmem = physmem_size + iomem_size - max_physmem; 3771da177e4SLinus Torvalds physmem_size -= highmem; 3781da177e4SLinus Torvalds } 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds high_physmem = uml_physmem + physmem_size; 3811da177e4SLinus Torvalds end_iomem = high_physmem + iomem_size; 3821da177e4SLinus Torvalds high_memory = (void *) end_iomem; 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds start_vm = VMALLOC_START; 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds virtmem_size = physmem_size; 38760a2988aSJeff Dike stack = (unsigned long) argv; 38860a2988aSJeff Dike stack &= ~(1024 * 1024 - 1); 38960a2988aSJeff Dike avail = stack - start_vm; 390ba180fd4SJeff Dike if (physmem_size > avail) 391ba180fd4SJeff Dike virtmem_size = avail; 3921da177e4SLinus Torvalds end_vm = start_vm + virtmem_size; 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds if (virtmem_size < physmem_size) 395d3878bb8SMasami Hiramatsu os_info("Kernel virtual memory size shrunk to %lu bytes\n", 3961da177e4SLinus Torvalds virtmem_size); 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds os_flush_stdout(); 3991da177e4SLinus Torvalds 40077bf4400SJeff Dike return start_uml(); 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds 4035b4236e1SMasami Hiramatsu int __init __weak read_initrd(void) 4045b4236e1SMasami Hiramatsu { 4055b4236e1SMasami Hiramatsu return 0; 4065b4236e1SMasami Hiramatsu } 4075b4236e1SMasami Hiramatsu 4081da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p) 4091da177e4SLinus Torvalds { 4100b9ba613SJason A. Donenfeld u8 rng_seed[32]; 4110b9ba613SJason A. Donenfeld 412b6323697SRichard Weinberger stack_protections((unsigned long) &init_thread_info); 413b6323697SRichard Weinberger setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); 414b6323697SRichard Weinberger mem_total_pages(physmem_size, iomem_size, highmem); 415b31297f0SVincent Whitchurch uml_dtb_init(); 4165b4236e1SMasami Hiramatsu read_initrd(); 417b6323697SRichard Weinberger 4181da177e4SLinus Torvalds paging_init(); 419*e6e4d33fSWolfram Sang strscpy(boot_command_line, command_line, COMMAND_LINE_SIZE); 4201da177e4SLinus Torvalds *cmdline_p = command_line; 421b4ffb6adSJeff Dike setup_hostinfo(host_info, sizeof host_info); 4220b9ba613SJason A. Donenfeld 4230b9ba613SJason A. Donenfeld if (os_getrandom(rng_seed, sizeof(rng_seed), 0) == sizeof(rng_seed)) { 4240b9ba613SJason A. Donenfeld add_bootloader_randomness(rng_seed, sizeof(rng_seed)); 4250b9ba613SJason A. Donenfeld memzero_explicit(rng_seed, sizeof(rng_seed)); 4260b9ba613SJason A. Donenfeld } 4271da177e4SLinus Torvalds } 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds void __init check_bugs(void) 4301da177e4SLinus Torvalds { 4311da177e4SLinus Torvalds arch_check_bugs(); 4328e367065SJeff Dike os_check_bugs(); 4331da177e4SLinus Torvalds } 4341da177e4SLinus Torvalds 435ed53a0d9SPeter Zijlstra void apply_ibt_endbr(s32 *start, s32 *end) 436ed53a0d9SPeter Zijlstra { 437ed53a0d9SPeter Zijlstra } 438ed53a0d9SPeter Zijlstra 43975085009SPeter Zijlstra void apply_retpolines(s32 *start, s32 *end) 44075085009SPeter Zijlstra { 44175085009SPeter Zijlstra } 44275085009SPeter Zijlstra 443564d9981SPeter Zijlstra void apply_returns(s32 *start, s32 *end) 444564d9981SPeter Zijlstra { 445564d9981SPeter Zijlstra } 446564d9981SPeter Zijlstra 4479a0b5817SGerd Hoffmann void apply_alternatives(struct alt_instr *start, struct alt_instr *end) 4489a0b5817SGerd Hoffmann { 4499a0b5817SGerd Hoffmann } 45088fc078aSPeter Zijlstra 45188fc078aSPeter Zijlstra void *text_poke(void *addr, const void *opcode, size_t len) 45288fc078aSPeter Zijlstra { 45388fc078aSPeter Zijlstra /* 45488fc078aSPeter Zijlstra * In UML, the only reference to this function is in 45588fc078aSPeter Zijlstra * apply_relocate_add(), which shouldn't ever actually call this 45688fc078aSPeter Zijlstra * because UML doesn't have live patching. 45788fc078aSPeter Zijlstra */ 45888fc078aSPeter Zijlstra WARN_ON(1); 45988fc078aSPeter Zijlstra 46088fc078aSPeter Zijlstra return memcpy(addr, opcode, len); 46188fc078aSPeter Zijlstra } 46288fc078aSPeter Zijlstra 46388fc078aSPeter Zijlstra void text_poke_sync(void) 46488fc078aSPeter Zijlstra { 46588fc078aSPeter Zijlstra } 46692dcd3d3SJohannes Berg 46792dcd3d3SJohannes Berg void uml_pm_wake(void) 46892dcd3d3SJohannes Berg { 46992dcd3d3SJohannes Berg pm_system_wakeup(); 47092dcd3d3SJohannes Berg } 47192dcd3d3SJohannes Berg 4721fb1abc8SJohannes Berg #ifdef CONFIG_PM_SLEEP 473a374b7cbSJohannes Berg static int um_suspend_valid(suspend_state_t state) 474a374b7cbSJohannes Berg { 475a374b7cbSJohannes Berg return state == PM_SUSPEND_MEM; 476a374b7cbSJohannes Berg } 477a374b7cbSJohannes Berg 478a374b7cbSJohannes Berg static int um_suspend_prepare(void) 479a374b7cbSJohannes Berg { 480a374b7cbSJohannes Berg um_irqs_suspend(); 481a374b7cbSJohannes Berg return 0; 482a374b7cbSJohannes Berg } 483a374b7cbSJohannes Berg 484a374b7cbSJohannes Berg static int um_suspend_enter(suspend_state_t state) 485a374b7cbSJohannes Berg { 486a374b7cbSJohannes Berg if (WARN_ON(state != PM_SUSPEND_MEM)) 487a374b7cbSJohannes Berg return -EINVAL; 488a374b7cbSJohannes Berg 489a374b7cbSJohannes Berg /* 490a374b7cbSJohannes Berg * This is identical to the idle sleep, but we've just 491a374b7cbSJohannes Berg * (during suspend) turned off all interrupt sources 492a374b7cbSJohannes Berg * except for the ones we want, so now we can only wake 493a374b7cbSJohannes Berg * up on something we actually want to wake up on. All 494a374b7cbSJohannes Berg * timing has also been suspended. 495a374b7cbSJohannes Berg */ 496a374b7cbSJohannes Berg um_idle_sleep(); 497a374b7cbSJohannes Berg return 0; 498a374b7cbSJohannes Berg } 499a374b7cbSJohannes Berg 500a374b7cbSJohannes Berg static void um_suspend_finish(void) 501a374b7cbSJohannes Berg { 502a374b7cbSJohannes Berg um_irqs_resume(); 503a374b7cbSJohannes Berg } 504a374b7cbSJohannes Berg 505a374b7cbSJohannes Berg const struct platform_suspend_ops um_suspend_ops = { 506a374b7cbSJohannes Berg .valid = um_suspend_valid, 507a374b7cbSJohannes Berg .prepare = um_suspend_prepare, 508a374b7cbSJohannes Berg .enter = um_suspend_enter, 509a374b7cbSJohannes Berg .finish = um_suspend_finish, 510a374b7cbSJohannes Berg }; 511a374b7cbSJohannes Berg 51292dcd3d3SJohannes Berg static int init_pm_wake_signal(void) 51392dcd3d3SJohannes Berg { 51492dcd3d3SJohannes Berg /* 51592dcd3d3SJohannes Berg * In external time-travel mode we can't use signals to wake up 51692dcd3d3SJohannes Berg * since that would mess with the scheduling. We'll have to do 51792dcd3d3SJohannes Berg * some additional work to support wakeup on virtio devices or 51892dcd3d3SJohannes Berg * similar, perhaps implementing a fake RTC controller that can 51992dcd3d3SJohannes Berg * trigger wakeup (and request the appropriate scheduling from 52092dcd3d3SJohannes Berg * the external scheduler when going to suspend.) 52192dcd3d3SJohannes Berg */ 52292dcd3d3SJohannes Berg if (time_travel_mode != TT_MODE_EXTERNAL) 52392dcd3d3SJohannes Berg register_pm_wake_signal(); 524a374b7cbSJohannes Berg 525a374b7cbSJohannes Berg suspend_set_ops(&um_suspend_ops); 526a374b7cbSJohannes Berg 52792dcd3d3SJohannes Berg return 0; 52892dcd3d3SJohannes Berg } 52992dcd3d3SJohannes Berg 53092dcd3d3SJohannes Berg late_initcall(init_pm_wake_signal); 53192dcd3d3SJohannes Berg #endif 532