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
69349b5cdSThomas Gleixner #include <linux/cpu.h>
7c5d4bb17SJeff Dike #include <linux/delay.h>
8c5d4bb17SJeff Dike #include <linux/init.h>
9c5d4bb17SJeff Dike #include <linux/mm.h>
10d8fb32f4SAnton Ivanov #include <linux/ctype.h>
11c5d4bb17SJeff Dike #include <linux/module.h>
12f39650deSAndy Shevchenko #include <linux/panic_notifier.h>
13c5d4bb17SJeff Dike #include <linux/seq_file.h>
14c5d4bb17SJeff Dike #include <linux/string.h>
15c5d4bb17SJeff Dike #include <linux/utsname.h>
165b408241SThomas Gleixner #include <linux/sched.h>
179164bb4aSIngo Molnar #include <linux/sched/task.h>
1804a41849SThomas Meyer #include <linux/kmsg_dump.h>
1992dcd3d3SJohannes Berg #include <linux/suspend.h>
200b9ba613SJason A. Donenfeld #include <linux/random.h>
219164bb4aSIngo Molnar
22c5d4bb17SJeff Dike #include <asm/processor.h>
23d8fb32f4SAnton Ivanov #include <asm/cpufeature.h>
2433a7d429SGeert Uytterhoeven #include <asm/sections.h>
25c5d4bb17SJeff Dike #include <asm/setup.h>
2637185b33SAl Viro #include <as-layout.h>
2737185b33SAl Viro #include <arch.h>
2837185b33SAl Viro #include <init.h>
2937185b33SAl Viro #include <kern.h>
3037185b33SAl Viro #include <kern_util.h>
3137185b33SAl Viro #include <mem_user.h>
3237185b33SAl Viro #include <os.h>
331da177e4SLinus Torvalds
34b31297f0SVincent Whitchurch #include "um_arch.h"
35b31297f0SVincent Whitchurch
36d7ffac33SThomas Meyer #define DEFAULT_COMMAND_LINE_ROOT "root=98:0"
37782b1f70SChristian Lamparter #define DEFAULT_COMMAND_LINE_CONSOLE "console=tty0"
381da177e4SLinus Torvalds
391d1497e1SJeff Dike /* Changed in add_arg and setup_arch, which run before SMP is started */
407a3a06d0SAlon Bar-Lev static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
411da177e4SLinus Torvalds
add_arg(char * arg)427a3a06d0SAlon Bar-Lev static void __init add_arg(char *arg)
431da177e4SLinus Torvalds {
441da177e4SLinus Torvalds if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
450936d4f3SMasami Hiramatsu os_warn("add_arg: Too many command line arguments!\n");
461da177e4SLinus Torvalds exit(1);
471da177e4SLinus Torvalds }
481da177e4SLinus Torvalds if (strlen(command_line) > 0)
491da177e4SLinus Torvalds strcat(command_line, " ");
501da177e4SLinus Torvalds strcat(command_line, arg);
511da177e4SLinus Torvalds }
521da177e4SLinus Torvalds
531d1497e1SJeff Dike /*
541d1497e1SJeff Dike * These fields are initialized at boot time and not changed.
551d1497e1SJeff Dike * XXX This structure is used only in the non-SMP case. Maybe this
561d1497e1SJeff Dike * should be moved to smp.c.
571d1497e1SJeff Dike */
581da177e4SLinus Torvalds struct cpuinfo_um boot_cpu_data = {
591da177e4SLinus Torvalds .loops_per_jiffy = 0,
60d8fb32f4SAnton Ivanov .ipi_pipe = { -1, -1 },
61d8fb32f4SAnton Ivanov .cache_alignment = L1_CACHE_BYTES,
62d8fb32f4SAnton Ivanov .x86_capability = { 0 }
631da177e4SLinus Torvalds };
641da177e4SLinus Torvalds
65d8fb32f4SAnton Ivanov EXPORT_SYMBOL(boot_cpu_data);
66d8fb32f4SAnton Ivanov
675b408241SThomas Gleixner union thread_union cpu0_irqstack
6833def849SJoe Perches __section(".data..init_irqstack") =
690500871fSDavid Howells { .thread_info = INIT_THREAD_INFO(init_task) };
705b408241SThomas Gleixner
71b4ffb6adSJeff Dike /* Changed in setup_arch, which is called in early boot */
72b4ffb6adSJeff Dike static char host_info[(__NEW_UTS_LEN + 1) * 5];
73b4ffb6adSJeff Dike
show_cpuinfo(struct seq_file * m,void * v)741da177e4SLinus Torvalds static int show_cpuinfo(struct seq_file *m, void *v)
751da177e4SLinus Torvalds {
76d8fb32f4SAnton Ivanov int i = 0;
771da177e4SLinus Torvalds
78d8fb32f4SAnton Ivanov seq_printf(m, "processor\t: %d\n", i);
791da177e4SLinus Torvalds seq_printf(m, "vendor_id\t: User Mode Linux\n");
801da177e4SLinus Torvalds seq_printf(m, "model name\t: UML\n");
816aa802ceSJeff Dike seq_printf(m, "mode\t\t: skas\n");
821da177e4SLinus Torvalds seq_printf(m, "host\t\t: %s\n", host_info);
83d8fb32f4SAnton Ivanov seq_printf(m, "fpu\t\t: %s\n", cpu_has(&boot_cpu_data, X86_FEATURE_FPU) ? "yes" : "no");
84d8fb32f4SAnton Ivanov seq_printf(m, "flags\t\t:");
85d8fb32f4SAnton Ivanov for (i = 0; i < 32*NCAPINTS; i++)
86d8fb32f4SAnton Ivanov if (cpu_has(&boot_cpu_data, i) && (x86_cap_flags[i] != NULL))
87d8fb32f4SAnton Ivanov seq_printf(m, " %s", x86_cap_flags[i]);
88d8fb32f4SAnton Ivanov seq_printf(m, "\n");
89d8fb32f4SAnton Ivanov seq_printf(m, "cache_alignment\t: %d\n", boot_cpu_data.cache_alignment);
90d8fb32f4SAnton Ivanov seq_printf(m, "bogomips\t: %lu.%02lu\n",
911da177e4SLinus Torvalds loops_per_jiffy/(500000/HZ),
921da177e4SLinus Torvalds (loops_per_jiffy/(5000/HZ)) % 100);
931da177e4SLinus Torvalds
94d8fb32f4SAnton Ivanov
95a5ed1ffaSJeff Dike return 0;
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds
c_start(struct seq_file * m,loff_t * pos)981da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
991da177e4SLinus Torvalds {
1002f2be510SPeter Foley return *pos < nr_cpu_ids ? &boot_cpu_data + *pos : NULL;
1011da177e4SLinus Torvalds }
1021da177e4SLinus Torvalds
c_next(struct seq_file * m,void * v,loff_t * pos)1031da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
1041da177e4SLinus Torvalds {
1051da177e4SLinus Torvalds ++*pos;
1061da177e4SLinus Torvalds return c_start(m, pos);
1071da177e4SLinus Torvalds }
1081da177e4SLinus Torvalds
c_stop(struct seq_file * m,void * v)1091da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
1101da177e4SLinus Torvalds {
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds
1135e7672ecSJeff Dike const struct seq_operations cpuinfo_op = {
1141da177e4SLinus Torvalds .start = c_start,
1151da177e4SLinus Torvalds .next = c_next,
1161da177e4SLinus Torvalds .stop = c_stop,
1171da177e4SLinus Torvalds .show = show_cpuinfo,
1181da177e4SLinus Torvalds };
1191da177e4SLinus Torvalds
1201da177e4SLinus Torvalds /* Set in linux_main */
1211da177e4SLinus Torvalds unsigned long uml_physmem;
12273395a00SAl Viro EXPORT_SYMBOL(uml_physmem);
12373395a00SAl Viro
1241d1497e1SJeff Dike unsigned long uml_reserved; /* Also modified in mem_init */
1251da177e4SLinus Torvalds unsigned long start_vm;
1261da177e4SLinus Torvalds unsigned long end_vm;
1271d1497e1SJeff Dike
1281d1497e1SJeff Dike /* Set in uml_ncpus_setup */
1291da177e4SLinus Torvalds int ncpus = 1;
1301da177e4SLinus Torvalds
1311da177e4SLinus Torvalds /* Set in early boot */
132d7ffac33SThomas Meyer static int have_root __initdata;
133d7ffac33SThomas Meyer static int have_console __initdata;
1341d1497e1SJeff Dike
1351d1497e1SJeff Dike /* Set in uml_mem_setup and modified in linux_main */
1360d644e91SChristian Lamparter long long physmem_size = 64 * 1024 * 1024;
1375d38f324SErel Geron EXPORT_SYMBOL(physmem_size);
1381da177e4SLinus Torvalds
1393af9c5beSWANG Cong static const char *usage_string =
1401da177e4SLinus Torvalds "User Mode Linux v%s\n"
1411da177e4SLinus Torvalds " available at http://user-mode-linux.sourceforge.net/\n\n";
1421da177e4SLinus Torvalds
uml_version_setup(char * line,int * add)1431da177e4SLinus Torvalds static int __init uml_version_setup(char *line, int *add)
1441da177e4SLinus Torvalds {
1450936d4f3SMasami Hiramatsu /* Explicitly use printf() to show version in stdout */
14696b644bdSSerge E. Hallyn printf("%s\n", init_utsname()->release);
1471da177e4SLinus Torvalds exit(0);
1481da177e4SLinus Torvalds
1491da177e4SLinus Torvalds return 0;
1501da177e4SLinus Torvalds }
1511da177e4SLinus Torvalds
1521da177e4SLinus Torvalds __uml_setup("--version", uml_version_setup,
1531da177e4SLinus Torvalds "--version\n"
1541da177e4SLinus Torvalds " Prints the version number of the kernel.\n\n"
1551da177e4SLinus Torvalds );
1561da177e4SLinus Torvalds
uml_root_setup(char * line,int * add)1571da177e4SLinus Torvalds static int __init uml_root_setup(char *line, int *add)
1581da177e4SLinus Torvalds {
1591da177e4SLinus Torvalds have_root = 1;
1601da177e4SLinus Torvalds return 0;
1611da177e4SLinus Torvalds }
1621da177e4SLinus Torvalds
1631da177e4SLinus Torvalds __uml_setup("root=", uml_root_setup,
1641da177e4SLinus Torvalds "root=<file containing the root fs>\n"
1651da177e4SLinus Torvalds " This is actually used by the generic kernel in exactly the same\n"
1661da177e4SLinus Torvalds " way as in any other kernel. If you configure a number of block\n"
1671da177e4SLinus Torvalds " devices and want to boot off something other than ubd0, you \n"
1681da177e4SLinus Torvalds " would use something like:\n"
1691da177e4SLinus Torvalds " root=/dev/ubd5\n\n"
1701da177e4SLinus Torvalds );
1711da177e4SLinus Torvalds
no_skas_debug_setup(char * line,int * add)172fbd55779SJeff Dike static int __init no_skas_debug_setup(char *line, int *add)
173fbd55779SJeff Dike {
1740936d4f3SMasami Hiramatsu os_warn("'debug' is not necessary to gdb UML in skas mode - run\n");
1750936d4f3SMasami Hiramatsu os_warn("'gdb linux'\n");
176fbd55779SJeff Dike
177fbd55779SJeff Dike return 0;
178fbd55779SJeff Dike }
179fbd55779SJeff Dike
180fbd55779SJeff Dike __uml_setup("debug", no_skas_debug_setup,
181fbd55779SJeff Dike "debug\n"
182fbd55779SJeff Dike " this flag is not needed to run gdb on UML in skas mode\n\n"
183fbd55779SJeff Dike );
184fbd55779SJeff Dike
uml_console_setup(char * line,int * add)185d7ffac33SThomas Meyer static int __init uml_console_setup(char *line, int *add)
186d7ffac33SThomas Meyer {
187d7ffac33SThomas Meyer have_console = 1;
188d7ffac33SThomas Meyer return 0;
189d7ffac33SThomas Meyer }
190d7ffac33SThomas Meyer
191d7ffac33SThomas Meyer __uml_setup("console=", uml_console_setup,
192d7ffac33SThomas Meyer "console=<preferred console>\n"
193d7ffac33SThomas Meyer " Specify the preferred console output driver\n\n"
194d7ffac33SThomas Meyer );
195d7ffac33SThomas Meyer
Usage(char * line,int * add)1961da177e4SLinus Torvalds static int __init Usage(char *line, int *add)
1971da177e4SLinus Torvalds {
1981da177e4SLinus Torvalds const char **p;
1991da177e4SLinus Torvalds
20096b644bdSSerge E. Hallyn printf(usage_string, init_utsname()->release);
2011da177e4SLinus Torvalds p = &__uml_help_start;
2020936d4f3SMasami Hiramatsu /* Explicitly use printf() to show help in stdout */
2031da177e4SLinus Torvalds while (p < &__uml_help_end) {
2041da177e4SLinus Torvalds printf("%s", *p);
2051da177e4SLinus Torvalds p++;
2061da177e4SLinus Torvalds }
2071da177e4SLinus Torvalds exit(0);
2081da177e4SLinus Torvalds return 0;
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds
2111da177e4SLinus Torvalds __uml_setup("--help", Usage,
2121da177e4SLinus Torvalds "--help\n"
2131da177e4SLinus Torvalds " Prints this message.\n\n"
2141da177e4SLinus Torvalds );
2151da177e4SLinus Torvalds
uml_checksetup(char * line,int * add)2166b7e9674SKarol Swietlicki static void __init uml_checksetup(char *line, int *add)
2171da177e4SLinus Torvalds {
2181da177e4SLinus Torvalds struct uml_param *p;
2191da177e4SLinus Torvalds
2201da177e4SLinus Torvalds p = &__uml_setup_start;
2211da177e4SLinus Torvalds while (p < &__uml_setup_end) {
2223af9c5beSWANG Cong size_t n;
2231da177e4SLinus Torvalds
2241da177e4SLinus Torvalds n = strlen(p->str);
225ba180fd4SJeff Dike if (!strncmp(line, p->str, n) && p->setup_func(line + n, add))
2266b7e9674SKarol Swietlicki return;
2271da177e4SLinus Torvalds p++;
2281da177e4SLinus Torvalds }
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds
uml_postsetup(void)2311da177e4SLinus Torvalds static void __init uml_postsetup(void)
2321da177e4SLinus Torvalds {
2331da177e4SLinus Torvalds initcall_t *p;
2341da177e4SLinus Torvalds
2351da177e4SLinus Torvalds p = &__uml_postsetup_start;
2361da177e4SLinus Torvalds while (p < &__uml_postsetup_end) {
2371da177e4SLinus Torvalds (*p)();
2381da177e4SLinus Torvalds p++;
2391da177e4SLinus Torvalds }
2401da177e4SLinus Torvalds return;
2411da177e4SLinus Torvalds }
2421da177e4SLinus Torvalds
panic_exit(struct notifier_block * self,unsigned long unused1,void * unused2)2430983a88bSJeff Dike static int panic_exit(struct notifier_block *self, unsigned long unused1,
2440983a88bSJeff Dike void *unused2)
2450983a88bSJeff Dike {
24604a41849SThomas Meyer kmsg_dump(KMSG_DUMP_PANIC);
2470983a88bSJeff Dike bust_spinlocks(1);
2480983a88bSJeff Dike bust_spinlocks(0);
2490983a88bSJeff Dike uml_exitcode = 1;
2500983a88bSJeff Dike os_dump_core();
251758dfdb9SGuilherme G. Piccoli
252758dfdb9SGuilherme G. Piccoli return NOTIFY_DONE;
2530983a88bSJeff Dike }
2540983a88bSJeff Dike
2550983a88bSJeff Dike static struct notifier_block panic_exit_notifier = {
2560983a88bSJeff Dike .notifier_call = panic_exit,
257758dfdb9SGuilherme G. Piccoli .priority = INT_MAX - 1, /* run as 2nd notifier, won't return */
2580983a88bSJeff Dike };
2590983a88bSJeff Dike
uml_finishsetup(void)26033bbc306SThomas Meyer void uml_finishsetup(void)
26133bbc306SThomas Meyer {
26233bbc306SThomas Meyer atomic_notifier_chain_register(&panic_notifier_list,
26333bbc306SThomas Meyer &panic_exit_notifier);
26433bbc306SThomas Meyer
26533bbc306SThomas Meyer uml_postsetup();
26633bbc306SThomas Meyer
26733bbc306SThomas Meyer new_thread_handler();
26833bbc306SThomas Meyer }
26933bbc306SThomas Meyer
2701da177e4SLinus Torvalds /* Set during early boot */
271bfc58e2bSJohannes Berg unsigned long stub_start;
272536788feSJeff Dike unsigned long task_size;
273536788feSJeff Dike EXPORT_SYMBOL(task_size);
274536788feSJeff Dike
275536788feSJeff Dike unsigned long host_task_size;
276536788feSJeff Dike
2771da177e4SLinus Torvalds unsigned long brk_start;
2781da177e4SLinus Torvalds unsigned long end_iomem;
2791da177e4SLinus Torvalds EXPORT_SYMBOL(end_iomem);
2801da177e4SLinus Torvalds
2811da177e4SLinus Torvalds #define MIN_VMALLOC (32 * 1024 * 1024)
2821da177e4SLinus Torvalds
parse_host_cpu_flags(char * line)283d8fb32f4SAnton Ivanov static void parse_host_cpu_flags(char *line)
284d8fb32f4SAnton Ivanov {
285d8fb32f4SAnton Ivanov int i;
286d8fb32f4SAnton Ivanov for (i = 0; i < 32*NCAPINTS; i++) {
287d8fb32f4SAnton Ivanov if ((x86_cap_flags[i] != NULL) && strstr(line, x86_cap_flags[i]))
2881aee0201SWan Jiabing set_cpu_cap(&boot_cpu_data, i);
289d8fb32f4SAnton Ivanov }
290d8fb32f4SAnton Ivanov }
parse_cache_line(char * line)291d8fb32f4SAnton Ivanov static void parse_cache_line(char *line)
292d8fb32f4SAnton Ivanov {
293d8fb32f4SAnton Ivanov long res;
294d8fb32f4SAnton Ivanov char *to_parse = strstr(line, ":");
295d8fb32f4SAnton Ivanov if (to_parse) {
296d8fb32f4SAnton Ivanov to_parse++;
297d8fb32f4SAnton Ivanov while (*to_parse != 0 && isspace(*to_parse)) {
298d8fb32f4SAnton Ivanov to_parse++;
299d8fb32f4SAnton Ivanov }
300d8fb32f4SAnton Ivanov if (kstrtoul(to_parse, 10, &res) == 0 && is_power_of_2(res))
301d8fb32f4SAnton Ivanov boot_cpu_data.cache_alignment = res;
302d8fb32f4SAnton Ivanov else
303d8fb32f4SAnton Ivanov boot_cpu_data.cache_alignment = L1_CACHE_BYTES;
304d8fb32f4SAnton Ivanov }
305d8fb32f4SAnton Ivanov }
306d8fb32f4SAnton Ivanov
linux_main(int argc,char ** argv)3077a3a06d0SAlon Bar-Lev int __init linux_main(int argc, char **argv)
3081da177e4SLinus Torvalds {
3091da177e4SLinus Torvalds unsigned long avail, diff;
3101da177e4SLinus Torvalds unsigned long virtmem_size, max_physmem;
31160a2988aSJeff Dike unsigned long stack;
3123af9c5beSWANG Cong unsigned int i;
3133af9c5beSWANG Cong int add;
3141da177e4SLinus Torvalds
3151da177e4SLinus Torvalds for (i = 1; i < argc; i++) {
316ba180fd4SJeff Dike if ((i == 1) && (argv[i][0] == ' '))
317ba180fd4SJeff Dike continue;
3181da177e4SLinus Torvalds add = 1;
3191da177e4SLinus Torvalds uml_checksetup(argv[i], &add);
3201da177e4SLinus Torvalds if (add)
3211da177e4SLinus Torvalds add_arg(argv[i]);
3221da177e4SLinus Torvalds }
3231da177e4SLinus Torvalds if (have_root == 0)
324d7ffac33SThomas Meyer add_arg(DEFAULT_COMMAND_LINE_ROOT);
325d7ffac33SThomas Meyer
326d7ffac33SThomas Meyer if (have_console == 0)
327d7ffac33SThomas Meyer add_arg(DEFAULT_COMMAND_LINE_CONSOLE);
3281da177e4SLinus Torvalds
32940fb16a3STom Spink host_task_size = os_get_top_address();
3306032aca0SJohannes Berg /* reserve a few pages for the stubs (taking care of data alignment) */
3316032aca0SJohannes Berg /* align the data portion */
3326032aca0SJohannes Berg BUILD_BUG_ON(!is_power_of_2(STUB_DATA_PAGES));
3336032aca0SJohannes Berg stub_start = (host_task_size - 1) & ~(STUB_DATA_PAGES * PAGE_SIZE - 1);
3346032aca0SJohannes Berg /* another page for the code portion */
3356032aca0SJohannes Berg stub_start -= PAGE_SIZE;
3366032aca0SJohannes Berg host_task_size = stub_start;
337bfc58e2bSJohannes Berg
338536788feSJeff Dike /*
339536788feSJeff Dike * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps
340536788feSJeff Dike * out
341536788feSJeff Dike */
342536788feSJeff Dike task_size = host_task_size & PGDIR_MASK;
343536788feSJeff Dike
344ba180fd4SJeff Dike /* OS sanity checks that need to happen before the kernel runs */
34560d339f6SGennady Sharapov os_early_checks();
346cb66504dSPaolo 'Blaisorblade' Giarrusso
347d8fb32f4SAnton Ivanov get_host_cpu_features(parse_host_cpu_flags, parse_cache_line);
348d8fb32f4SAnton Ivanov
3491da177e4SLinus Torvalds brk_start = (unsigned long) sbrk(0);
35077bf4400SJeff Dike
351ba180fd4SJeff Dike /*
352ba180fd4SJeff Dike * Increase physical memory size for exec-shield users
353ba180fd4SJeff Dike * so they actually get what they asked for. This should
354ba180fd4SJeff Dike * add zero for non-exec shield users
355ba180fd4SJeff Dike */
3561da177e4SLinus Torvalds
3571da177e4SLinus Torvalds diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
3581da177e4SLinus Torvalds if (diff > 1024 * 1024) {
359d3878bb8SMasami Hiramatsu os_info("Adding %ld bytes to physical memory to account for "
3601da177e4SLinus Torvalds "exec-shield gap\n", diff);
3611da177e4SLinus Torvalds physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
3621da177e4SLinus Torvalds }
3631da177e4SLinus Torvalds
36405eacfd0SNicolas Iooss uml_physmem = (unsigned long) __binary_start & PAGE_MASK;
3651da177e4SLinus Torvalds
3661da177e4SLinus Torvalds /* Reserve up to 4M after the current brk */
3671da177e4SLinus Torvalds uml_reserved = ROUND_4M(brk_start) + (1 << 22);
3681da177e4SLinus Torvalds
36996b644bdSSerge E. Hallyn setup_machinename(init_utsname()->machine);
3701da177e4SLinus Torvalds
3711da177e4SLinus Torvalds highmem = 0;
3721da177e4SLinus Torvalds iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
373536788feSJeff Dike max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC;
3741da177e4SLinus Torvalds
375ba180fd4SJeff Dike /*
376ba180fd4SJeff Dike * Zones have to begin on a 1 << MAX_ORDER page boundary,
3771da177e4SLinus Torvalds * so this makes sure that's true for highmem
3781da177e4SLinus Torvalds */
3791da177e4SLinus Torvalds max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
3801da177e4SLinus Torvalds if (physmem_size + iomem_size > max_physmem) {
3811da177e4SLinus Torvalds highmem = physmem_size + iomem_size - max_physmem;
3821da177e4SLinus Torvalds physmem_size -= highmem;
3831da177e4SLinus Torvalds }
3841da177e4SLinus Torvalds
3851da177e4SLinus Torvalds high_physmem = uml_physmem + physmem_size;
3861da177e4SLinus Torvalds end_iomem = high_physmem + iomem_size;
3871da177e4SLinus Torvalds high_memory = (void *) end_iomem;
3881da177e4SLinus Torvalds
3891da177e4SLinus Torvalds start_vm = VMALLOC_START;
3901da177e4SLinus Torvalds
3911da177e4SLinus Torvalds virtmem_size = physmem_size;
39260a2988aSJeff Dike stack = (unsigned long) argv;
39360a2988aSJeff Dike stack &= ~(1024 * 1024 - 1);
39460a2988aSJeff Dike avail = stack - start_vm;
395ba180fd4SJeff Dike if (physmem_size > avail)
396ba180fd4SJeff Dike virtmem_size = avail;
3971da177e4SLinus Torvalds end_vm = start_vm + virtmem_size;
3981da177e4SLinus Torvalds
3991da177e4SLinus Torvalds if (virtmem_size < physmem_size)
400d3878bb8SMasami Hiramatsu os_info("Kernel virtual memory size shrunk to %lu bytes\n",
4011da177e4SLinus Torvalds virtmem_size);
4021da177e4SLinus Torvalds
4031da177e4SLinus Torvalds os_flush_stdout();
4041da177e4SLinus Torvalds
40577bf4400SJeff Dike return start_uml();
4061da177e4SLinus Torvalds }
4071da177e4SLinus Torvalds
read_initrd(void)4085b4236e1SMasami Hiramatsu int __init __weak read_initrd(void)
4095b4236e1SMasami Hiramatsu {
4105b4236e1SMasami Hiramatsu return 0;
4115b4236e1SMasami Hiramatsu }
4125b4236e1SMasami Hiramatsu
setup_arch(char ** cmdline_p)4131da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p)
4141da177e4SLinus Torvalds {
4150b9ba613SJason A. Donenfeld u8 rng_seed[32];
4160b9ba613SJason A. Donenfeld
417b6323697SRichard Weinberger stack_protections((unsigned long) &init_thread_info);
418b6323697SRichard Weinberger setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
419b6323697SRichard Weinberger mem_total_pages(physmem_size, iomem_size, highmem);
420b31297f0SVincent Whitchurch uml_dtb_init();
4215b4236e1SMasami Hiramatsu read_initrd();
422b6323697SRichard Weinberger
4231da177e4SLinus Torvalds paging_init();
424e6e4d33fSWolfram Sang strscpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
4251da177e4SLinus Torvalds *cmdline_p = command_line;
426b4ffb6adSJeff Dike setup_hostinfo(host_info, sizeof host_info);
4270b9ba613SJason A. Donenfeld
4280b9ba613SJason A. Donenfeld if (os_getrandom(rng_seed, sizeof(rng_seed), 0) == sizeof(rng_seed)) {
4290b9ba613SJason A. Donenfeld add_bootloader_randomness(rng_seed, sizeof(rng_seed));
4300b9ba613SJason A. Donenfeld memzero_explicit(rng_seed, sizeof(rng_seed));
4310b9ba613SJason A. Donenfeld }
4321da177e4SLinus Torvalds }
4331da177e4SLinus Torvalds
arch_cpu_finalize_init(void)4349349b5cdSThomas Gleixner void __init arch_cpu_finalize_init(void)
4351da177e4SLinus Torvalds {
4361da177e4SLinus Torvalds arch_check_bugs();
4378e367065SJeff Dike os_check_bugs();
4381da177e4SLinus Torvalds }
4391da177e4SLinus Torvalds
apply_seal_endbr(s32 * start,s32 * end)440*be0fffa5SPeter Zijlstra void apply_seal_endbr(s32 *start, s32 *end)
441ed53a0d9SPeter Zijlstra {
442ed53a0d9SPeter Zijlstra }
443ed53a0d9SPeter Zijlstra
apply_retpolines(s32 * start,s32 * end)44475085009SPeter Zijlstra void apply_retpolines(s32 *start, s32 *end)
44575085009SPeter Zijlstra {
44675085009SPeter Zijlstra }
44775085009SPeter Zijlstra
apply_returns(s32 * start,s32 * end)448564d9981SPeter Zijlstra void apply_returns(s32 *start, s32 *end)
449564d9981SPeter Zijlstra {
450564d9981SPeter Zijlstra }
451564d9981SPeter Zijlstra
apply_fineibt(s32 * start_retpoline,s32 * end_retpoline,s32 * start_cfi,s32 * end_cfi)452931ab636SPeter Zijlstra void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
453931ab636SPeter Zijlstra s32 *start_cfi, s32 *end_cfi)
454931ab636SPeter Zijlstra {
455931ab636SPeter Zijlstra }
456931ab636SPeter Zijlstra
apply_alternatives(struct alt_instr * start,struct alt_instr * end)4579a0b5817SGerd Hoffmann void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
4589a0b5817SGerd Hoffmann {
4599a0b5817SGerd Hoffmann }
46088fc078aSPeter Zijlstra
text_poke(void * addr,const void * opcode,size_t len)46188fc078aSPeter Zijlstra void *text_poke(void *addr, const void *opcode, size_t len)
46288fc078aSPeter Zijlstra {
46388fc078aSPeter Zijlstra /*
46488fc078aSPeter Zijlstra * In UML, the only reference to this function is in
46588fc078aSPeter Zijlstra * apply_relocate_add(), which shouldn't ever actually call this
46688fc078aSPeter Zijlstra * because UML doesn't have live patching.
46788fc078aSPeter Zijlstra */
46888fc078aSPeter Zijlstra WARN_ON(1);
46988fc078aSPeter Zijlstra
47088fc078aSPeter Zijlstra return memcpy(addr, opcode, len);
47188fc078aSPeter Zijlstra }
47288fc078aSPeter Zijlstra
text_poke_sync(void)47388fc078aSPeter Zijlstra void text_poke_sync(void)
47488fc078aSPeter Zijlstra {
47588fc078aSPeter Zijlstra }
47692dcd3d3SJohannes Berg
uml_pm_wake(void)47792dcd3d3SJohannes Berg void uml_pm_wake(void)
47892dcd3d3SJohannes Berg {
47992dcd3d3SJohannes Berg pm_system_wakeup();
48092dcd3d3SJohannes Berg }
48192dcd3d3SJohannes Berg
4821fb1abc8SJohannes Berg #ifdef CONFIG_PM_SLEEP
um_suspend_valid(suspend_state_t state)483a374b7cbSJohannes Berg static int um_suspend_valid(suspend_state_t state)
484a374b7cbSJohannes Berg {
485a374b7cbSJohannes Berg return state == PM_SUSPEND_MEM;
486a374b7cbSJohannes Berg }
487a374b7cbSJohannes Berg
um_suspend_prepare(void)488a374b7cbSJohannes Berg static int um_suspend_prepare(void)
489a374b7cbSJohannes Berg {
490a374b7cbSJohannes Berg um_irqs_suspend();
491a374b7cbSJohannes Berg return 0;
492a374b7cbSJohannes Berg }
493a374b7cbSJohannes Berg
um_suspend_enter(suspend_state_t state)494a374b7cbSJohannes Berg static int um_suspend_enter(suspend_state_t state)
495a374b7cbSJohannes Berg {
496a374b7cbSJohannes Berg if (WARN_ON(state != PM_SUSPEND_MEM))
497a374b7cbSJohannes Berg return -EINVAL;
498a374b7cbSJohannes Berg
499a374b7cbSJohannes Berg /*
500a374b7cbSJohannes Berg * This is identical to the idle sleep, but we've just
501a374b7cbSJohannes Berg * (during suspend) turned off all interrupt sources
502a374b7cbSJohannes Berg * except for the ones we want, so now we can only wake
503a374b7cbSJohannes Berg * up on something we actually want to wake up on. All
504a374b7cbSJohannes Berg * timing has also been suspended.
505a374b7cbSJohannes Berg */
506a374b7cbSJohannes Berg um_idle_sleep();
507a374b7cbSJohannes Berg return 0;
508a374b7cbSJohannes Berg }
509a374b7cbSJohannes Berg
um_suspend_finish(void)510a374b7cbSJohannes Berg static void um_suspend_finish(void)
511a374b7cbSJohannes Berg {
512a374b7cbSJohannes Berg um_irqs_resume();
513a374b7cbSJohannes Berg }
514a374b7cbSJohannes Berg
515a374b7cbSJohannes Berg const struct platform_suspend_ops um_suspend_ops = {
516a374b7cbSJohannes Berg .valid = um_suspend_valid,
517a374b7cbSJohannes Berg .prepare = um_suspend_prepare,
518a374b7cbSJohannes Berg .enter = um_suspend_enter,
519a374b7cbSJohannes Berg .finish = um_suspend_finish,
520a374b7cbSJohannes Berg };
521a374b7cbSJohannes Berg
init_pm_wake_signal(void)52292dcd3d3SJohannes Berg static int init_pm_wake_signal(void)
52392dcd3d3SJohannes Berg {
52492dcd3d3SJohannes Berg /*
52592dcd3d3SJohannes Berg * In external time-travel mode we can't use signals to wake up
52692dcd3d3SJohannes Berg * since that would mess with the scheduling. We'll have to do
52792dcd3d3SJohannes Berg * some additional work to support wakeup on virtio devices or
52892dcd3d3SJohannes Berg * similar, perhaps implementing a fake RTC controller that can
52992dcd3d3SJohannes Berg * trigger wakeup (and request the appropriate scheduling from
53092dcd3d3SJohannes Berg * the external scheduler when going to suspend.)
53192dcd3d3SJohannes Berg */
53292dcd3d3SJohannes Berg if (time_travel_mode != TT_MODE_EXTERNAL)
53392dcd3d3SJohannes Berg register_pm_wake_signal();
534a374b7cbSJohannes Berg
535a374b7cbSJohannes Berg suspend_set_ops(&um_suspend_ops);
536a374b7cbSJohannes Berg
53792dcd3d3SJohannes Berg return 0;
53892dcd3d3SJohannes Berg }
53992dcd3d3SJohannes Berg
54092dcd3d3SJohannes Berg late_initcall(init_pm_wake_signal);
54192dcd3d3SJohannes Berg #endif
542