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