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> 199164bb4aSIngo Molnar 20c5d4bb17SJeff Dike #include <asm/processor.h> 21d8fb32f4SAnton Ivanov #include <asm/cpufeature.h> 2233a7d429SGeert Uytterhoeven #include <asm/sections.h> 23c5d4bb17SJeff Dike #include <asm/setup.h> 2437185b33SAl Viro #include <as-layout.h> 2537185b33SAl Viro #include <arch.h> 2637185b33SAl Viro #include <init.h> 2737185b33SAl Viro #include <kern.h> 2837185b33SAl Viro #include <kern_util.h> 2937185b33SAl Viro #include <mem_user.h> 3037185b33SAl Viro #include <os.h> 311da177e4SLinus Torvalds 32b31297f0SVincent Whitchurch #include "um_arch.h" 33b31297f0SVincent Whitchurch 34d7ffac33SThomas Meyer #define DEFAULT_COMMAND_LINE_ROOT "root=98:0" 35d7ffac33SThomas Meyer #define DEFAULT_COMMAND_LINE_CONSOLE "console=tty" 361da177e4SLinus Torvalds 371d1497e1SJeff Dike /* Changed in add_arg and setup_arch, which run before SMP is started */ 387a3a06d0SAlon Bar-Lev static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 }; 391da177e4SLinus Torvalds 407a3a06d0SAlon Bar-Lev static void __init add_arg(char *arg) 411da177e4SLinus Torvalds { 421da177e4SLinus Torvalds if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) { 430936d4f3SMasami Hiramatsu os_warn("add_arg: Too many command line arguments!\n"); 441da177e4SLinus Torvalds exit(1); 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds if (strlen(command_line) > 0) 471da177e4SLinus Torvalds strcat(command_line, " "); 481da177e4SLinus Torvalds strcat(command_line, arg); 491da177e4SLinus Torvalds } 501da177e4SLinus Torvalds 511d1497e1SJeff Dike /* 521d1497e1SJeff Dike * These fields are initialized at boot time and not changed. 531d1497e1SJeff Dike * XXX This structure is used only in the non-SMP case. Maybe this 541d1497e1SJeff Dike * should be moved to smp.c. 551d1497e1SJeff Dike */ 561da177e4SLinus Torvalds struct cpuinfo_um boot_cpu_data = { 571da177e4SLinus Torvalds .loops_per_jiffy = 0, 58d8fb32f4SAnton Ivanov .ipi_pipe = { -1, -1 }, 59d8fb32f4SAnton Ivanov .cache_alignment = L1_CACHE_BYTES, 60d8fb32f4SAnton Ivanov .x86_capability = { 0 } 611da177e4SLinus Torvalds }; 621da177e4SLinus Torvalds 63d8fb32f4SAnton Ivanov EXPORT_SYMBOL(boot_cpu_data); 64d8fb32f4SAnton Ivanov 655b408241SThomas Gleixner union thread_union cpu0_irqstack 6633def849SJoe Perches __section(".data..init_irqstack") = 670500871fSDavid Howells { .thread_info = INIT_THREAD_INFO(init_task) }; 685b408241SThomas Gleixner 69b4ffb6adSJeff Dike /* Changed in setup_arch, which is called in early boot */ 70b4ffb6adSJeff Dike static char host_info[(__NEW_UTS_LEN + 1) * 5]; 71b4ffb6adSJeff Dike 721da177e4SLinus Torvalds static int show_cpuinfo(struct seq_file *m, void *v) 731da177e4SLinus Torvalds { 74d8fb32f4SAnton Ivanov int i = 0; 751da177e4SLinus Torvalds 76d8fb32f4SAnton Ivanov seq_printf(m, "processor\t: %d\n", i); 771da177e4SLinus Torvalds seq_printf(m, "vendor_id\t: User Mode Linux\n"); 781da177e4SLinus Torvalds seq_printf(m, "model name\t: UML\n"); 796aa802ceSJeff Dike seq_printf(m, "mode\t\t: skas\n"); 801da177e4SLinus Torvalds seq_printf(m, "host\t\t: %s\n", host_info); 81d8fb32f4SAnton Ivanov seq_printf(m, "fpu\t\t: %s\n", cpu_has(&boot_cpu_data, X86_FEATURE_FPU) ? "yes" : "no"); 82d8fb32f4SAnton Ivanov seq_printf(m, "flags\t\t:"); 83d8fb32f4SAnton Ivanov for (i = 0; i < 32*NCAPINTS; i++) 84d8fb32f4SAnton Ivanov if (cpu_has(&boot_cpu_data, i) && (x86_cap_flags[i] != NULL)) 85d8fb32f4SAnton Ivanov seq_printf(m, " %s", x86_cap_flags[i]); 86d8fb32f4SAnton Ivanov seq_printf(m, "\n"); 87d8fb32f4SAnton Ivanov seq_printf(m, "cache_alignment\t: %d\n", boot_cpu_data.cache_alignment); 88d8fb32f4SAnton Ivanov seq_printf(m, "bogomips\t: %lu.%02lu\n", 891da177e4SLinus Torvalds loops_per_jiffy/(500000/HZ), 901da177e4SLinus Torvalds (loops_per_jiffy/(5000/HZ)) % 100); 911da177e4SLinus Torvalds 92d8fb32f4SAnton Ivanov 93a5ed1ffaSJeff Dike return 0; 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos) 971da177e4SLinus Torvalds { 981da177e4SLinus Torvalds return *pos < NR_CPUS ? cpu_data + *pos : NULL; 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos) 1021da177e4SLinus Torvalds { 1031da177e4SLinus Torvalds ++*pos; 1041da177e4SLinus Torvalds return c_start(m, pos); 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v) 1081da177e4SLinus Torvalds { 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds 1115e7672ecSJeff Dike const struct seq_operations cpuinfo_op = { 1121da177e4SLinus Torvalds .start = c_start, 1131da177e4SLinus Torvalds .next = c_next, 1141da177e4SLinus Torvalds .stop = c_stop, 1151da177e4SLinus Torvalds .show = show_cpuinfo, 1161da177e4SLinus Torvalds }; 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds /* Set in linux_main */ 1191da177e4SLinus Torvalds unsigned long uml_physmem; 12073395a00SAl Viro EXPORT_SYMBOL(uml_physmem); 12173395a00SAl Viro 1221d1497e1SJeff Dike unsigned long uml_reserved; /* Also modified in mem_init */ 1231da177e4SLinus Torvalds unsigned long start_vm; 1241da177e4SLinus Torvalds unsigned long end_vm; 1251d1497e1SJeff Dike 1261d1497e1SJeff Dike /* Set in uml_ncpus_setup */ 1271da177e4SLinus Torvalds int ncpus = 1; 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds /* Set in early boot */ 130d7ffac33SThomas Meyer static int have_root __initdata; 131d7ffac33SThomas Meyer static int have_console __initdata; 1321d1497e1SJeff Dike 1331d1497e1SJeff Dike /* Set in uml_mem_setup and modified in linux_main */ 134ae173816SJeff Dike long long physmem_size = 32 * 1024 * 1024; 1355d38f324SErel Geron EXPORT_SYMBOL(physmem_size); 1361da177e4SLinus Torvalds 1373af9c5beSWANG Cong static const char *usage_string = 1381da177e4SLinus Torvalds "User Mode Linux v%s\n" 1391da177e4SLinus Torvalds " available at http://user-mode-linux.sourceforge.net/\n\n"; 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds static int __init uml_version_setup(char *line, int *add) 1421da177e4SLinus Torvalds { 1430936d4f3SMasami Hiramatsu /* Explicitly use printf() to show version in stdout */ 14496b644bdSSerge E. Hallyn printf("%s\n", init_utsname()->release); 1451da177e4SLinus Torvalds exit(0); 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds return 0; 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds __uml_setup("--version", uml_version_setup, 1511da177e4SLinus Torvalds "--version\n" 1521da177e4SLinus Torvalds " Prints the version number of the kernel.\n\n" 1531da177e4SLinus Torvalds ); 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds static int __init uml_root_setup(char *line, int *add) 1561da177e4SLinus Torvalds { 1571da177e4SLinus Torvalds have_root = 1; 1581da177e4SLinus Torvalds return 0; 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds __uml_setup("root=", uml_root_setup, 1621da177e4SLinus Torvalds "root=<file containing the root fs>\n" 1631da177e4SLinus Torvalds " This is actually used by the generic kernel in exactly the same\n" 1641da177e4SLinus Torvalds " way as in any other kernel. If you configure a number of block\n" 1651da177e4SLinus Torvalds " devices and want to boot off something other than ubd0, you \n" 1661da177e4SLinus Torvalds " would use something like:\n" 1671da177e4SLinus Torvalds " root=/dev/ubd5\n\n" 1681da177e4SLinus Torvalds ); 1691da177e4SLinus Torvalds 170fbd55779SJeff Dike static int __init no_skas_debug_setup(char *line, int *add) 171fbd55779SJeff Dike { 1720936d4f3SMasami Hiramatsu os_warn("'debug' is not necessary to gdb UML in skas mode - run\n"); 1730936d4f3SMasami Hiramatsu os_warn("'gdb linux'\n"); 174fbd55779SJeff Dike 175fbd55779SJeff Dike return 0; 176fbd55779SJeff Dike } 177fbd55779SJeff Dike 178fbd55779SJeff Dike __uml_setup("debug", no_skas_debug_setup, 179fbd55779SJeff Dike "debug\n" 180fbd55779SJeff Dike " this flag is not needed to run gdb on UML in skas mode\n\n" 181fbd55779SJeff Dike ); 182fbd55779SJeff Dike 183d7ffac33SThomas Meyer static int __init uml_console_setup(char *line, int *add) 184d7ffac33SThomas Meyer { 185d7ffac33SThomas Meyer have_console = 1; 186d7ffac33SThomas Meyer return 0; 187d7ffac33SThomas Meyer } 188d7ffac33SThomas Meyer 189d7ffac33SThomas Meyer __uml_setup("console=", uml_console_setup, 190d7ffac33SThomas Meyer "console=<preferred console>\n" 191d7ffac33SThomas Meyer " Specify the preferred console output driver\n\n" 192d7ffac33SThomas Meyer ); 193d7ffac33SThomas Meyer 1941da177e4SLinus Torvalds static int __init Usage(char *line, int *add) 1951da177e4SLinus Torvalds { 1961da177e4SLinus Torvalds const char **p; 1971da177e4SLinus Torvalds 19896b644bdSSerge E. Hallyn printf(usage_string, init_utsname()->release); 1991da177e4SLinus Torvalds p = &__uml_help_start; 2000936d4f3SMasami Hiramatsu /* Explicitly use printf() to show help in stdout */ 2011da177e4SLinus Torvalds while (p < &__uml_help_end) { 2021da177e4SLinus Torvalds printf("%s", *p); 2031da177e4SLinus Torvalds p++; 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds exit(0); 2061da177e4SLinus Torvalds return 0; 2071da177e4SLinus Torvalds } 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds __uml_setup("--help", Usage, 2101da177e4SLinus Torvalds "--help\n" 2111da177e4SLinus Torvalds " Prints this message.\n\n" 2121da177e4SLinus Torvalds ); 2131da177e4SLinus Torvalds 2146b7e9674SKarol Swietlicki static void __init uml_checksetup(char *line, int *add) 2151da177e4SLinus Torvalds { 2161da177e4SLinus Torvalds struct uml_param *p; 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds p = &__uml_setup_start; 2191da177e4SLinus Torvalds while (p < &__uml_setup_end) { 2203af9c5beSWANG Cong size_t n; 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds n = strlen(p->str); 223ba180fd4SJeff Dike if (!strncmp(line, p->str, n) && p->setup_func(line + n, add)) 2246b7e9674SKarol Swietlicki return; 2251da177e4SLinus Torvalds p++; 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds static void __init uml_postsetup(void) 2301da177e4SLinus Torvalds { 2311da177e4SLinus Torvalds initcall_t *p; 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds p = &__uml_postsetup_start; 2341da177e4SLinus Torvalds while (p < &__uml_postsetup_end) { 2351da177e4SLinus Torvalds (*p)(); 2361da177e4SLinus Torvalds p++; 2371da177e4SLinus Torvalds } 2381da177e4SLinus Torvalds return; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 2410983a88bSJeff Dike static int panic_exit(struct notifier_block *self, unsigned long unused1, 2420983a88bSJeff Dike void *unused2) 2430983a88bSJeff Dike { 24404a41849SThomas Meyer kmsg_dump(KMSG_DUMP_PANIC); 2450983a88bSJeff Dike bust_spinlocks(1); 2460983a88bSJeff Dike bust_spinlocks(0); 2470983a88bSJeff Dike uml_exitcode = 1; 2480983a88bSJeff Dike os_dump_core(); 2490983a88bSJeff Dike return 0; 2500983a88bSJeff Dike } 2510983a88bSJeff Dike 2520983a88bSJeff Dike static struct notifier_block panic_exit_notifier = { 2530983a88bSJeff Dike .notifier_call = panic_exit, 2540983a88bSJeff Dike .next = NULL, 2550983a88bSJeff Dike .priority = 0 2560983a88bSJeff Dike }; 2570983a88bSJeff Dike 25833bbc306SThomas Meyer void uml_finishsetup(void) 25933bbc306SThomas Meyer { 26033bbc306SThomas Meyer atomic_notifier_chain_register(&panic_notifier_list, 26133bbc306SThomas Meyer &panic_exit_notifier); 26233bbc306SThomas Meyer 26333bbc306SThomas Meyer uml_postsetup(); 26433bbc306SThomas Meyer 26533bbc306SThomas Meyer new_thread_handler(); 26633bbc306SThomas Meyer } 26733bbc306SThomas Meyer 2681da177e4SLinus Torvalds /* Set during early boot */ 269bfc58e2bSJohannes Berg unsigned long stub_start; 270536788feSJeff Dike unsigned long task_size; 271536788feSJeff Dike EXPORT_SYMBOL(task_size); 272536788feSJeff Dike 273536788feSJeff Dike unsigned long host_task_size; 274536788feSJeff Dike 2751da177e4SLinus Torvalds unsigned long brk_start; 2761da177e4SLinus Torvalds unsigned long end_iomem; 2771da177e4SLinus Torvalds EXPORT_SYMBOL(end_iomem); 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds #define MIN_VMALLOC (32 * 1024 * 1024) 2801da177e4SLinus Torvalds 281d8fb32f4SAnton Ivanov static void parse_host_cpu_flags(char *line) 282d8fb32f4SAnton Ivanov { 283d8fb32f4SAnton Ivanov int i; 284d8fb32f4SAnton Ivanov for (i = 0; i < 32*NCAPINTS; i++) { 285d8fb32f4SAnton Ivanov if ((x86_cap_flags[i] != NULL) && strstr(line, x86_cap_flags[i])) 2861aee0201SWan Jiabing set_cpu_cap(&boot_cpu_data, i); 287d8fb32f4SAnton Ivanov } 288d8fb32f4SAnton Ivanov } 289d8fb32f4SAnton Ivanov static void parse_cache_line(char *line) 290d8fb32f4SAnton Ivanov { 291d8fb32f4SAnton Ivanov long res; 292d8fb32f4SAnton Ivanov char *to_parse = strstr(line, ":"); 293d8fb32f4SAnton Ivanov if (to_parse) { 294d8fb32f4SAnton Ivanov to_parse++; 295d8fb32f4SAnton Ivanov while (*to_parse != 0 && isspace(*to_parse)) { 296d8fb32f4SAnton Ivanov to_parse++; 297d8fb32f4SAnton Ivanov } 298d8fb32f4SAnton Ivanov if (kstrtoul(to_parse, 10, &res) == 0 && is_power_of_2(res)) 299d8fb32f4SAnton Ivanov boot_cpu_data.cache_alignment = res; 300d8fb32f4SAnton Ivanov else 301d8fb32f4SAnton Ivanov boot_cpu_data.cache_alignment = L1_CACHE_BYTES; 302d8fb32f4SAnton Ivanov } 303d8fb32f4SAnton Ivanov } 304d8fb32f4SAnton Ivanov 3057a3a06d0SAlon Bar-Lev int __init linux_main(int argc, char **argv) 3061da177e4SLinus Torvalds { 3071da177e4SLinus Torvalds unsigned long avail, diff; 3081da177e4SLinus Torvalds unsigned long virtmem_size, max_physmem; 30960a2988aSJeff Dike unsigned long stack; 3103af9c5beSWANG Cong unsigned int i; 3113af9c5beSWANG Cong int add; 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds for (i = 1; i < argc; i++) { 314ba180fd4SJeff Dike if ((i == 1) && (argv[i][0] == ' ')) 315ba180fd4SJeff Dike continue; 3161da177e4SLinus Torvalds add = 1; 3171da177e4SLinus Torvalds uml_checksetup(argv[i], &add); 3181da177e4SLinus Torvalds if (add) 3191da177e4SLinus Torvalds add_arg(argv[i]); 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds if (have_root == 0) 322d7ffac33SThomas Meyer add_arg(DEFAULT_COMMAND_LINE_ROOT); 323d7ffac33SThomas Meyer 324d7ffac33SThomas Meyer if (have_console == 0) 325d7ffac33SThomas Meyer add_arg(DEFAULT_COMMAND_LINE_CONSOLE); 3261da177e4SLinus Torvalds 32740fb16a3STom Spink host_task_size = os_get_top_address(); 328bfc58e2bSJohannes Berg /* reserve two pages for the stubs */ 329bfc58e2bSJohannes Berg host_task_size -= 2 * PAGE_SIZE; 330bfc58e2bSJohannes Berg stub_start = host_task_size; 331bfc58e2bSJohannes Berg 332536788feSJeff Dike /* 333536788feSJeff Dike * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps 334536788feSJeff Dike * out 335536788feSJeff Dike */ 336536788feSJeff Dike task_size = host_task_size & PGDIR_MASK; 337536788feSJeff Dike 338ba180fd4SJeff Dike /* OS sanity checks that need to happen before the kernel runs */ 33960d339f6SGennady Sharapov os_early_checks(); 340cb66504dSPaolo 'Blaisorblade' Giarrusso 341d8fb32f4SAnton Ivanov get_host_cpu_features(parse_host_cpu_flags, parse_cache_line); 342d8fb32f4SAnton Ivanov 3431da177e4SLinus Torvalds brk_start = (unsigned long) sbrk(0); 34477bf4400SJeff Dike 345ba180fd4SJeff Dike /* 346ba180fd4SJeff Dike * Increase physical memory size for exec-shield users 347ba180fd4SJeff Dike * so they actually get what they asked for. This should 348ba180fd4SJeff Dike * add zero for non-exec shield users 349ba180fd4SJeff Dike */ 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); 3521da177e4SLinus Torvalds if (diff > 1024 * 1024) { 353d3878bb8SMasami Hiramatsu os_info("Adding %ld bytes to physical memory to account for " 3541da177e4SLinus Torvalds "exec-shield gap\n", diff); 3551da177e4SLinus Torvalds physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds 35805eacfd0SNicolas Iooss uml_physmem = (unsigned long) __binary_start & PAGE_MASK; 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds /* Reserve up to 4M after the current brk */ 3611da177e4SLinus Torvalds uml_reserved = ROUND_4M(brk_start) + (1 << 22); 3621da177e4SLinus Torvalds 36396b644bdSSerge E. Hallyn setup_machinename(init_utsname()->machine); 3641da177e4SLinus Torvalds 3651da177e4SLinus Torvalds highmem = 0; 3661da177e4SLinus Torvalds iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; 367536788feSJeff Dike max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC; 3681da177e4SLinus Torvalds 369ba180fd4SJeff Dike /* 370ba180fd4SJeff Dike * Zones have to begin on a 1 << MAX_ORDER page boundary, 3711da177e4SLinus Torvalds * so this makes sure that's true for highmem 3721da177e4SLinus Torvalds */ 3731da177e4SLinus Torvalds max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1); 3741da177e4SLinus Torvalds if (physmem_size + iomem_size > max_physmem) { 3751da177e4SLinus Torvalds highmem = physmem_size + iomem_size - max_physmem; 3761da177e4SLinus Torvalds physmem_size -= highmem; 3771da177e4SLinus Torvalds } 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds high_physmem = uml_physmem + physmem_size; 3801da177e4SLinus Torvalds end_iomem = high_physmem + iomem_size; 3811da177e4SLinus Torvalds high_memory = (void *) end_iomem; 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds start_vm = VMALLOC_START; 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds virtmem_size = physmem_size; 38660a2988aSJeff Dike stack = (unsigned long) argv; 38760a2988aSJeff Dike stack &= ~(1024 * 1024 - 1); 38860a2988aSJeff Dike avail = stack - start_vm; 389ba180fd4SJeff Dike if (physmem_size > avail) 390ba180fd4SJeff Dike virtmem_size = avail; 3911da177e4SLinus Torvalds end_vm = start_vm + virtmem_size; 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds if (virtmem_size < physmem_size) 394d3878bb8SMasami Hiramatsu os_info("Kernel virtual memory size shrunk to %lu bytes\n", 3951da177e4SLinus Torvalds virtmem_size); 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds os_flush_stdout(); 3981da177e4SLinus Torvalds 39977bf4400SJeff Dike return start_uml(); 4001da177e4SLinus Torvalds } 4011da177e4SLinus Torvalds 4025b4236e1SMasami Hiramatsu int __init __weak read_initrd(void) 4035b4236e1SMasami Hiramatsu { 4045b4236e1SMasami Hiramatsu return 0; 4055b4236e1SMasami Hiramatsu } 4065b4236e1SMasami Hiramatsu 4071da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p) 4081da177e4SLinus Torvalds { 409b6323697SRichard Weinberger stack_protections((unsigned long) &init_thread_info); 410b6323697SRichard Weinberger setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); 411b6323697SRichard Weinberger mem_total_pages(physmem_size, iomem_size, highmem); 412b31297f0SVincent Whitchurch uml_dtb_init(); 4135b4236e1SMasami Hiramatsu read_initrd(); 414b6323697SRichard Weinberger 4151da177e4SLinus Torvalds paging_init(); 41619bf7e7aSAlon Bar-Lev strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); 4171da177e4SLinus Torvalds *cmdline_p = command_line; 418b4ffb6adSJeff Dike setup_hostinfo(host_info, sizeof host_info); 4191da177e4SLinus Torvalds } 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds void __init check_bugs(void) 4221da177e4SLinus Torvalds { 4231da177e4SLinus Torvalds arch_check_bugs(); 4248e367065SJeff Dike os_check_bugs(); 4251da177e4SLinus Torvalds } 4261da177e4SLinus Torvalds 427*ed53a0d9SPeter Zijlstra void apply_ibt_endbr(s32 *start, s32 *end) 428*ed53a0d9SPeter Zijlstra { 429*ed53a0d9SPeter Zijlstra } 430*ed53a0d9SPeter Zijlstra 43175085009SPeter Zijlstra void apply_retpolines(s32 *start, s32 *end) 43275085009SPeter Zijlstra { 43375085009SPeter Zijlstra } 43475085009SPeter Zijlstra 4359a0b5817SGerd Hoffmann void apply_alternatives(struct alt_instr *start, struct alt_instr *end) 4369a0b5817SGerd Hoffmann { 4379a0b5817SGerd Hoffmann } 43888fc078aSPeter Zijlstra 43988fc078aSPeter Zijlstra void *text_poke(void *addr, const void *opcode, size_t len) 44088fc078aSPeter Zijlstra { 44188fc078aSPeter Zijlstra /* 44288fc078aSPeter Zijlstra * In UML, the only reference to this function is in 44388fc078aSPeter Zijlstra * apply_relocate_add(), which shouldn't ever actually call this 44488fc078aSPeter Zijlstra * because UML doesn't have live patching. 44588fc078aSPeter Zijlstra */ 44688fc078aSPeter Zijlstra WARN_ON(1); 44788fc078aSPeter Zijlstra 44888fc078aSPeter Zijlstra return memcpy(addr, opcode, len); 44988fc078aSPeter Zijlstra } 45088fc078aSPeter Zijlstra 45188fc078aSPeter Zijlstra void text_poke_sync(void) 45288fc078aSPeter Zijlstra { 45388fc078aSPeter Zijlstra } 45492dcd3d3SJohannes Berg 45592dcd3d3SJohannes Berg void uml_pm_wake(void) 45692dcd3d3SJohannes Berg { 45792dcd3d3SJohannes Berg pm_system_wakeup(); 45892dcd3d3SJohannes Berg } 45992dcd3d3SJohannes Berg 4601fb1abc8SJohannes Berg #ifdef CONFIG_PM_SLEEP 461a374b7cbSJohannes Berg static int um_suspend_valid(suspend_state_t state) 462a374b7cbSJohannes Berg { 463a374b7cbSJohannes Berg return state == PM_SUSPEND_MEM; 464a374b7cbSJohannes Berg } 465a374b7cbSJohannes Berg 466a374b7cbSJohannes Berg static int um_suspend_prepare(void) 467a374b7cbSJohannes Berg { 468a374b7cbSJohannes Berg um_irqs_suspend(); 469a374b7cbSJohannes Berg return 0; 470a374b7cbSJohannes Berg } 471a374b7cbSJohannes Berg 472a374b7cbSJohannes Berg static int um_suspend_enter(suspend_state_t state) 473a374b7cbSJohannes Berg { 474a374b7cbSJohannes Berg if (WARN_ON(state != PM_SUSPEND_MEM)) 475a374b7cbSJohannes Berg return -EINVAL; 476a374b7cbSJohannes Berg 477a374b7cbSJohannes Berg /* 478a374b7cbSJohannes Berg * This is identical to the idle sleep, but we've just 479a374b7cbSJohannes Berg * (during suspend) turned off all interrupt sources 480a374b7cbSJohannes Berg * except for the ones we want, so now we can only wake 481a374b7cbSJohannes Berg * up on something we actually want to wake up on. All 482a374b7cbSJohannes Berg * timing has also been suspended. 483a374b7cbSJohannes Berg */ 484a374b7cbSJohannes Berg um_idle_sleep(); 485a374b7cbSJohannes Berg return 0; 486a374b7cbSJohannes Berg } 487a374b7cbSJohannes Berg 488a374b7cbSJohannes Berg static void um_suspend_finish(void) 489a374b7cbSJohannes Berg { 490a374b7cbSJohannes Berg um_irqs_resume(); 491a374b7cbSJohannes Berg } 492a374b7cbSJohannes Berg 493a374b7cbSJohannes Berg const struct platform_suspend_ops um_suspend_ops = { 494a374b7cbSJohannes Berg .valid = um_suspend_valid, 495a374b7cbSJohannes Berg .prepare = um_suspend_prepare, 496a374b7cbSJohannes Berg .enter = um_suspend_enter, 497a374b7cbSJohannes Berg .finish = um_suspend_finish, 498a374b7cbSJohannes Berg }; 499a374b7cbSJohannes Berg 50092dcd3d3SJohannes Berg static int init_pm_wake_signal(void) 50192dcd3d3SJohannes Berg { 50292dcd3d3SJohannes Berg /* 50392dcd3d3SJohannes Berg * In external time-travel mode we can't use signals to wake up 50492dcd3d3SJohannes Berg * since that would mess with the scheduling. We'll have to do 50592dcd3d3SJohannes Berg * some additional work to support wakeup on virtio devices or 50692dcd3d3SJohannes Berg * similar, perhaps implementing a fake RTC controller that can 50792dcd3d3SJohannes Berg * trigger wakeup (and request the appropriate scheduling from 50892dcd3d3SJohannes Berg * the external scheduler when going to suspend.) 50992dcd3d3SJohannes Berg */ 51092dcd3d3SJohannes Berg if (time_travel_mode != TT_MODE_EXTERNAL) 51192dcd3d3SJohannes Berg register_pm_wake_signal(); 512a374b7cbSJohannes Berg 513a374b7cbSJohannes Berg suspend_set_ops(&um_suspend_ops); 514a374b7cbSJohannes Berg 51592dcd3d3SJohannes Berg return 0; 51692dcd3d3SJohannes Berg } 51792dcd3d3SJohannes Berg 51892dcd3d3SJohannes Berg late_initcall(init_pm_wake_signal); 51992dcd3d3SJohannes Berg #endif 520