xref: /openbmc/linux/arch/um/kernel/um_arch.c (revision 6032aca0)
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"
36782b1f70SChristian Lamparter #define DEFAULT_COMMAND_LINE_CONSOLE "console=tty0"
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 {
992f2be510SPeter Foley 	return *pos < nr_cpu_ids ? &boot_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();
250758dfdb9SGuilherme G. Piccoli 
251758dfdb9SGuilherme G. Piccoli 	return NOTIFY_DONE;
2520983a88bSJeff Dike }
2530983a88bSJeff Dike 
2540983a88bSJeff Dike static struct notifier_block panic_exit_notifier = {
2550983a88bSJeff Dike 	.notifier_call	= panic_exit,
256758dfdb9SGuilherme G. Piccoli 	.priority	= INT_MAX - 1, /* run as 2nd notifier, won't return */
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();
329*6032aca0SJohannes Berg 	/* reserve a few pages for the stubs (taking care of data alignment) */
330*6032aca0SJohannes Berg 	/* align the data portion */
331*6032aca0SJohannes Berg 	BUILD_BUG_ON(!is_power_of_2(STUB_DATA_PAGES));
332*6032aca0SJohannes Berg 	stub_start = (host_task_size - 1) & ~(STUB_DATA_PAGES * PAGE_SIZE - 1);
333*6032aca0SJohannes Berg 	/* another page for the code portion */
334*6032aca0SJohannes Berg 	stub_start -= PAGE_SIZE;
335*6032aca0SJohannes Berg 	host_task_size = stub_start;
336bfc58e2bSJohannes Berg 
337536788feSJeff Dike 	/*
338536788feSJeff Dike 	 * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps
339536788feSJeff Dike 	 * out
340536788feSJeff Dike 	 */
341536788feSJeff Dike 	task_size = host_task_size & PGDIR_MASK;
342536788feSJeff Dike 
343ba180fd4SJeff Dike 	/* OS sanity checks that need to happen before the kernel runs */
34460d339f6SGennady Sharapov 	os_early_checks();
345cb66504dSPaolo 'Blaisorblade' Giarrusso 
346d8fb32f4SAnton Ivanov 	get_host_cpu_features(parse_host_cpu_flags, parse_cache_line);
347d8fb32f4SAnton Ivanov 
3481da177e4SLinus Torvalds 	brk_start = (unsigned long) sbrk(0);
34977bf4400SJeff Dike 
350ba180fd4SJeff Dike 	/*
351ba180fd4SJeff Dike 	 * Increase physical memory size for exec-shield users
352ba180fd4SJeff Dike 	 * so they actually get what they asked for. This should
353ba180fd4SJeff Dike 	 * add zero for non-exec shield users
354ba180fd4SJeff Dike 	 */
3551da177e4SLinus Torvalds 
3561da177e4SLinus Torvalds 	diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
3571da177e4SLinus Torvalds 	if (diff > 1024 * 1024) {
358d3878bb8SMasami Hiramatsu 		os_info("Adding %ld bytes to physical memory to account for "
3591da177e4SLinus Torvalds 			"exec-shield gap\n", diff);
3601da177e4SLinus Torvalds 		physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
3611da177e4SLinus Torvalds 	}
3621da177e4SLinus Torvalds 
36305eacfd0SNicolas Iooss 	uml_physmem = (unsigned long) __binary_start & PAGE_MASK;
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 	/* Reserve up to 4M after the current brk */
3661da177e4SLinus Torvalds 	uml_reserved = ROUND_4M(brk_start) + (1 << 22);
3671da177e4SLinus Torvalds 
36896b644bdSSerge E. Hallyn 	setup_machinename(init_utsname()->machine);
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	highmem = 0;
3711da177e4SLinus Torvalds 	iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
372536788feSJeff Dike 	max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC;
3731da177e4SLinus Torvalds 
374ba180fd4SJeff Dike 	/*
375ba180fd4SJeff Dike 	 * Zones have to begin on a 1 << MAX_ORDER page boundary,
3761da177e4SLinus Torvalds 	 * so this makes sure that's true for highmem
3771da177e4SLinus Torvalds 	 */
3781da177e4SLinus Torvalds 	max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
3791da177e4SLinus Torvalds 	if (physmem_size + iomem_size > max_physmem) {
3801da177e4SLinus Torvalds 		highmem = physmem_size + iomem_size - max_physmem;
3811da177e4SLinus Torvalds 		physmem_size -= highmem;
3821da177e4SLinus Torvalds 	}
3831da177e4SLinus Torvalds 
3841da177e4SLinus Torvalds 	high_physmem = uml_physmem + physmem_size;
3851da177e4SLinus Torvalds 	end_iomem = high_physmem + iomem_size;
3861da177e4SLinus Torvalds 	high_memory = (void *) end_iomem;
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	start_vm = VMALLOC_START;
3891da177e4SLinus Torvalds 
3901da177e4SLinus Torvalds 	virtmem_size = physmem_size;
39160a2988aSJeff Dike 	stack = (unsigned long) argv;
39260a2988aSJeff Dike 	stack &= ~(1024 * 1024 - 1);
39360a2988aSJeff Dike 	avail = stack - start_vm;
394ba180fd4SJeff Dike 	if (physmem_size > avail)
395ba180fd4SJeff Dike 		virtmem_size = avail;
3961da177e4SLinus Torvalds 	end_vm = start_vm + virtmem_size;
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds 	if (virtmem_size < physmem_size)
399d3878bb8SMasami Hiramatsu 		os_info("Kernel virtual memory size shrunk to %lu bytes\n",
4001da177e4SLinus Torvalds 			virtmem_size);
4011da177e4SLinus Torvalds 
4021da177e4SLinus Torvalds 	os_flush_stdout();
4031da177e4SLinus Torvalds 
40477bf4400SJeff Dike 	return start_uml();
4051da177e4SLinus Torvalds }
4061da177e4SLinus Torvalds 
4075b4236e1SMasami Hiramatsu int __init __weak read_initrd(void)
4085b4236e1SMasami Hiramatsu {
4095b4236e1SMasami Hiramatsu 	return 0;
4105b4236e1SMasami Hiramatsu }
4115b4236e1SMasami Hiramatsu 
4121da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p)
4131da177e4SLinus Torvalds {
4140b9ba613SJason A. Donenfeld 	u8 rng_seed[32];
4150b9ba613SJason A. Donenfeld 
416b6323697SRichard Weinberger 	stack_protections((unsigned long) &init_thread_info);
417b6323697SRichard Weinberger 	setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
418b6323697SRichard Weinberger 	mem_total_pages(physmem_size, iomem_size, highmem);
419b31297f0SVincent Whitchurch 	uml_dtb_init();
4205b4236e1SMasami Hiramatsu 	read_initrd();
421b6323697SRichard Weinberger 
4221da177e4SLinus Torvalds 	paging_init();
423e6e4d33fSWolfram Sang 	strscpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
4241da177e4SLinus Torvalds 	*cmdline_p = command_line;
425b4ffb6adSJeff Dike 	setup_hostinfo(host_info, sizeof host_info);
4260b9ba613SJason A. Donenfeld 
4270b9ba613SJason A. Donenfeld 	if (os_getrandom(rng_seed, sizeof(rng_seed), 0) == sizeof(rng_seed)) {
4280b9ba613SJason A. Donenfeld 		add_bootloader_randomness(rng_seed, sizeof(rng_seed));
4290b9ba613SJason A. Donenfeld 		memzero_explicit(rng_seed, sizeof(rng_seed));
4300b9ba613SJason A. Donenfeld 	}
4311da177e4SLinus Torvalds }
4321da177e4SLinus Torvalds 
4331da177e4SLinus Torvalds void __init check_bugs(void)
4341da177e4SLinus Torvalds {
4351da177e4SLinus Torvalds 	arch_check_bugs();
4368e367065SJeff Dike 	os_check_bugs();
4371da177e4SLinus Torvalds }
4381da177e4SLinus Torvalds 
439ed53a0d9SPeter Zijlstra void apply_ibt_endbr(s32 *start, s32 *end)
440ed53a0d9SPeter Zijlstra {
441ed53a0d9SPeter Zijlstra }
442ed53a0d9SPeter Zijlstra 
44375085009SPeter Zijlstra void apply_retpolines(s32 *start, s32 *end)
44475085009SPeter Zijlstra {
44575085009SPeter Zijlstra }
44675085009SPeter Zijlstra 
447564d9981SPeter Zijlstra void apply_returns(s32 *start, s32 *end)
448564d9981SPeter Zijlstra {
449564d9981SPeter Zijlstra }
450564d9981SPeter Zijlstra 
451931ab636SPeter Zijlstra void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
452931ab636SPeter Zijlstra 		   s32 *start_cfi, s32 *end_cfi)
453931ab636SPeter Zijlstra {
454931ab636SPeter Zijlstra }
455931ab636SPeter Zijlstra 
4569a0b5817SGerd Hoffmann void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
4579a0b5817SGerd Hoffmann {
4589a0b5817SGerd Hoffmann }
45988fc078aSPeter Zijlstra 
46088fc078aSPeter Zijlstra void *text_poke(void *addr, const void *opcode, size_t len)
46188fc078aSPeter Zijlstra {
46288fc078aSPeter Zijlstra 	/*
46388fc078aSPeter Zijlstra 	 * In UML, the only reference to this function is in
46488fc078aSPeter Zijlstra 	 * apply_relocate_add(), which shouldn't ever actually call this
46588fc078aSPeter Zijlstra 	 * because UML doesn't have live patching.
46688fc078aSPeter Zijlstra 	 */
46788fc078aSPeter Zijlstra 	WARN_ON(1);
46888fc078aSPeter Zijlstra 
46988fc078aSPeter Zijlstra 	return memcpy(addr, opcode, len);
47088fc078aSPeter Zijlstra }
47188fc078aSPeter Zijlstra 
47288fc078aSPeter Zijlstra void text_poke_sync(void)
47388fc078aSPeter Zijlstra {
47488fc078aSPeter Zijlstra }
47592dcd3d3SJohannes Berg 
47692dcd3d3SJohannes Berg void uml_pm_wake(void)
47792dcd3d3SJohannes Berg {
47892dcd3d3SJohannes Berg 	pm_system_wakeup();
47992dcd3d3SJohannes Berg }
48092dcd3d3SJohannes Berg 
4811fb1abc8SJohannes Berg #ifdef CONFIG_PM_SLEEP
482a374b7cbSJohannes Berg static int um_suspend_valid(suspend_state_t state)
483a374b7cbSJohannes Berg {
484a374b7cbSJohannes Berg 	return state == PM_SUSPEND_MEM;
485a374b7cbSJohannes Berg }
486a374b7cbSJohannes Berg 
487a374b7cbSJohannes Berg static int um_suspend_prepare(void)
488a374b7cbSJohannes Berg {
489a374b7cbSJohannes Berg 	um_irqs_suspend();
490a374b7cbSJohannes Berg 	return 0;
491a374b7cbSJohannes Berg }
492a374b7cbSJohannes Berg 
493a374b7cbSJohannes Berg static int um_suspend_enter(suspend_state_t state)
494a374b7cbSJohannes Berg {
495a374b7cbSJohannes Berg 	if (WARN_ON(state != PM_SUSPEND_MEM))
496a374b7cbSJohannes Berg 		return -EINVAL;
497a374b7cbSJohannes Berg 
498a374b7cbSJohannes Berg 	/*
499a374b7cbSJohannes Berg 	 * This is identical to the idle sleep, but we've just
500a374b7cbSJohannes Berg 	 * (during suspend) turned off all interrupt sources
501a374b7cbSJohannes Berg 	 * except for the ones we want, so now we can only wake
502a374b7cbSJohannes Berg 	 * up on something we actually want to wake up on. All
503a374b7cbSJohannes Berg 	 * timing has also been suspended.
504a374b7cbSJohannes Berg 	 */
505a374b7cbSJohannes Berg 	um_idle_sleep();
506a374b7cbSJohannes Berg 	return 0;
507a374b7cbSJohannes Berg }
508a374b7cbSJohannes Berg 
509a374b7cbSJohannes Berg static void um_suspend_finish(void)
510a374b7cbSJohannes Berg {
511a374b7cbSJohannes Berg 	um_irqs_resume();
512a374b7cbSJohannes Berg }
513a374b7cbSJohannes Berg 
514a374b7cbSJohannes Berg const struct platform_suspend_ops um_suspend_ops = {
515a374b7cbSJohannes Berg 	.valid = um_suspend_valid,
516a374b7cbSJohannes Berg 	.prepare = um_suspend_prepare,
517a374b7cbSJohannes Berg 	.enter = um_suspend_enter,
518a374b7cbSJohannes Berg 	.finish = um_suspend_finish,
519a374b7cbSJohannes Berg };
520a374b7cbSJohannes Berg 
52192dcd3d3SJohannes Berg static int init_pm_wake_signal(void)
52292dcd3d3SJohannes Berg {
52392dcd3d3SJohannes Berg 	/*
52492dcd3d3SJohannes Berg 	 * In external time-travel mode we can't use signals to wake up
52592dcd3d3SJohannes Berg 	 * since that would mess with the scheduling. We'll have to do
52692dcd3d3SJohannes Berg 	 * some additional work to support wakeup on virtio devices or
52792dcd3d3SJohannes Berg 	 * similar, perhaps implementing a fake RTC controller that can
52892dcd3d3SJohannes Berg 	 * trigger wakeup (and request the appropriate scheduling from
52992dcd3d3SJohannes Berg 	 * the external scheduler when going to suspend.)
53092dcd3d3SJohannes Berg 	 */
53192dcd3d3SJohannes Berg 	if (time_travel_mode != TT_MODE_EXTERNAL)
53292dcd3d3SJohannes Berg 		register_pm_wake_signal();
533a374b7cbSJohannes Berg 
534a374b7cbSJohannes Berg 	suspend_set_ops(&um_suspend_ops);
535a374b7cbSJohannes Berg 
53692dcd3d3SJohannes Berg 	return 0;
53792dcd3d3SJohannes Berg }
53892dcd3d3SJohannes Berg 
53992dcd3d3SJohannes Berg late_initcall(init_pm_wake_signal);
54092dcd3d3SJohannes Berg #endif
541