xref: /openbmc/linux/arch/um/kernel/um_arch.c (revision ed53a0d9)
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