xref: /openbmc/linux/arch/um/kernel/um_arch.c (revision bfc58e2b)
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>
9c5d4bb17SJeff Dike #include <linux/module.h>
10c5d4bb17SJeff Dike #include <linux/seq_file.h>
11c5d4bb17SJeff Dike #include <linux/string.h>
12c5d4bb17SJeff Dike #include <linux/utsname.h>
135b408241SThomas Gleixner #include <linux/sched.h>
149164bb4aSIngo Molnar #include <linux/sched/task.h>
1504a41849SThomas Meyer #include <linux/kmsg_dump.h>
1692dcd3d3SJohannes Berg #include <linux/suspend.h>
179164bb4aSIngo Molnar 
18c5d4bb17SJeff Dike #include <asm/processor.h>
1933a7d429SGeert Uytterhoeven #include <asm/sections.h>
20c5d4bb17SJeff Dike #include <asm/setup.h>
2137185b33SAl Viro #include <as-layout.h>
2237185b33SAl Viro #include <arch.h>
2337185b33SAl Viro #include <init.h>
2437185b33SAl Viro #include <kern.h>
2537185b33SAl Viro #include <kern_util.h>
2637185b33SAl Viro #include <mem_user.h>
2737185b33SAl Viro #include <os.h>
281da177e4SLinus Torvalds 
29d7ffac33SThomas Meyer #define DEFAULT_COMMAND_LINE_ROOT "root=98:0"
30d7ffac33SThomas Meyer #define DEFAULT_COMMAND_LINE_CONSOLE "console=tty"
311da177e4SLinus Torvalds 
321d1497e1SJeff Dike /* Changed in add_arg and setup_arch, which run before SMP is started */
337a3a06d0SAlon Bar-Lev static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
341da177e4SLinus Torvalds 
357a3a06d0SAlon Bar-Lev static void __init add_arg(char *arg)
361da177e4SLinus Torvalds {
371da177e4SLinus Torvalds 	if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
380936d4f3SMasami Hiramatsu 		os_warn("add_arg: Too many command line arguments!\n");
391da177e4SLinus Torvalds 		exit(1);
401da177e4SLinus Torvalds 	}
411da177e4SLinus Torvalds 	if (strlen(command_line) > 0)
421da177e4SLinus Torvalds 		strcat(command_line, " ");
431da177e4SLinus Torvalds 	strcat(command_line, arg);
441da177e4SLinus Torvalds }
451da177e4SLinus Torvalds 
461d1497e1SJeff Dike /*
471d1497e1SJeff Dike  * These fields are initialized at boot time and not changed.
481d1497e1SJeff Dike  * XXX This structure is used only in the non-SMP case.  Maybe this
491d1497e1SJeff Dike  * should be moved to smp.c.
501d1497e1SJeff Dike  */
511da177e4SLinus Torvalds struct cpuinfo_um boot_cpu_data = {
521da177e4SLinus Torvalds 	.loops_per_jiffy	= 0,
531da177e4SLinus Torvalds 	.ipi_pipe		= { -1, -1 }
541da177e4SLinus Torvalds };
551da177e4SLinus Torvalds 
565b408241SThomas Gleixner union thread_union cpu0_irqstack
5733def849SJoe Perches 	__section(".data..init_irqstack") =
580500871fSDavid Howells 		{ .thread_info = INIT_THREAD_INFO(init_task) };
595b408241SThomas Gleixner 
60b4ffb6adSJeff Dike /* Changed in setup_arch, which is called in early boot */
61b4ffb6adSJeff Dike static char host_info[(__NEW_UTS_LEN + 1) * 5];
62b4ffb6adSJeff Dike 
631da177e4SLinus Torvalds static int show_cpuinfo(struct seq_file *m, void *v)
641da177e4SLinus Torvalds {
651da177e4SLinus Torvalds 	int index = 0;
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds 	seq_printf(m, "processor\t: %d\n", index);
681da177e4SLinus Torvalds 	seq_printf(m, "vendor_id\t: User Mode Linux\n");
691da177e4SLinus Torvalds 	seq_printf(m, "model name\t: UML\n");
706aa802ceSJeff Dike 	seq_printf(m, "mode\t\t: skas\n");
711da177e4SLinus Torvalds 	seq_printf(m, "host\t\t: %s\n", host_info);
721da177e4SLinus Torvalds 	seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
731da177e4SLinus Torvalds 		   loops_per_jiffy/(500000/HZ),
741da177e4SLinus Torvalds 		   (loops_per_jiffy/(5000/HZ)) % 100);
751da177e4SLinus Torvalds 
76a5ed1ffaSJeff Dike 	return 0;
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
801da177e4SLinus Torvalds {
811da177e4SLinus Torvalds 	return *pos < NR_CPUS ? cpu_data + *pos : NULL;
821da177e4SLinus Torvalds }
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
851da177e4SLinus Torvalds {
861da177e4SLinus Torvalds 	++*pos;
871da177e4SLinus Torvalds 	return c_start(m, pos);
881da177e4SLinus Torvalds }
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
911da177e4SLinus Torvalds {
921da177e4SLinus Torvalds }
931da177e4SLinus Torvalds 
945e7672ecSJeff Dike const struct seq_operations cpuinfo_op = {
951da177e4SLinus Torvalds 	.start	= c_start,
961da177e4SLinus Torvalds 	.next	= c_next,
971da177e4SLinus Torvalds 	.stop	= c_stop,
981da177e4SLinus Torvalds 	.show	= show_cpuinfo,
991da177e4SLinus Torvalds };
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds /* Set in linux_main */
1021da177e4SLinus Torvalds unsigned long uml_physmem;
10373395a00SAl Viro EXPORT_SYMBOL(uml_physmem);
10473395a00SAl Viro 
1051d1497e1SJeff Dike unsigned long uml_reserved; /* Also modified in mem_init */
1061da177e4SLinus Torvalds unsigned long start_vm;
1071da177e4SLinus Torvalds unsigned long end_vm;
1081d1497e1SJeff Dike 
1091d1497e1SJeff Dike /* Set in uml_ncpus_setup */
1101da177e4SLinus Torvalds int ncpus = 1;
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds /* Set in early boot */
113d7ffac33SThomas Meyer static int have_root __initdata;
114d7ffac33SThomas Meyer static int have_console __initdata;
1151d1497e1SJeff Dike 
1161d1497e1SJeff Dike /* Set in uml_mem_setup and modified in linux_main */
117ae173816SJeff Dike long long physmem_size = 32 * 1024 * 1024;
1185d38f324SErel Geron EXPORT_SYMBOL(physmem_size);
1191da177e4SLinus Torvalds 
1203af9c5beSWANG Cong static const char *usage_string =
1211da177e4SLinus Torvalds "User Mode Linux v%s\n"
1221da177e4SLinus Torvalds "	available at http://user-mode-linux.sourceforge.net/\n\n";
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds static int __init uml_version_setup(char *line, int *add)
1251da177e4SLinus Torvalds {
1260936d4f3SMasami Hiramatsu 	/* Explicitly use printf() to show version in stdout */
12796b644bdSSerge E. Hallyn 	printf("%s\n", init_utsname()->release);
1281da177e4SLinus Torvalds 	exit(0);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 	return 0;
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds __uml_setup("--version", uml_version_setup,
1341da177e4SLinus Torvalds "--version\n"
1351da177e4SLinus Torvalds "    Prints the version number of the kernel.\n\n"
1361da177e4SLinus Torvalds );
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds static int __init uml_root_setup(char *line, int *add)
1391da177e4SLinus Torvalds {
1401da177e4SLinus Torvalds 	have_root = 1;
1411da177e4SLinus Torvalds 	return 0;
1421da177e4SLinus Torvalds }
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds __uml_setup("root=", uml_root_setup,
1451da177e4SLinus Torvalds "root=<file containing the root fs>\n"
1461da177e4SLinus Torvalds "    This is actually used by the generic kernel in exactly the same\n"
1471da177e4SLinus Torvalds "    way as in any other kernel. If you configure a number of block\n"
1481da177e4SLinus Torvalds "    devices and want to boot off something other than ubd0, you \n"
1491da177e4SLinus Torvalds "    would use something like:\n"
1501da177e4SLinus Torvalds "        root=/dev/ubd5\n\n"
1511da177e4SLinus Torvalds );
1521da177e4SLinus Torvalds 
153fbd55779SJeff Dike static int __init no_skas_debug_setup(char *line, int *add)
154fbd55779SJeff Dike {
1550936d4f3SMasami Hiramatsu 	os_warn("'debug' is not necessary to gdb UML in skas mode - run\n");
1560936d4f3SMasami Hiramatsu 	os_warn("'gdb linux'\n");
157fbd55779SJeff Dike 
158fbd55779SJeff Dike 	return 0;
159fbd55779SJeff Dike }
160fbd55779SJeff Dike 
161fbd55779SJeff Dike __uml_setup("debug", no_skas_debug_setup,
162fbd55779SJeff Dike "debug\n"
163fbd55779SJeff Dike "    this flag is not needed to run gdb on UML in skas mode\n\n"
164fbd55779SJeff Dike );
165fbd55779SJeff Dike 
166d7ffac33SThomas Meyer static int __init uml_console_setup(char *line, int *add)
167d7ffac33SThomas Meyer {
168d7ffac33SThomas Meyer 	have_console = 1;
169d7ffac33SThomas Meyer 	return 0;
170d7ffac33SThomas Meyer }
171d7ffac33SThomas Meyer 
172d7ffac33SThomas Meyer __uml_setup("console=", uml_console_setup,
173d7ffac33SThomas Meyer "console=<preferred console>\n"
174d7ffac33SThomas Meyer "    Specify the preferred console output driver\n\n"
175d7ffac33SThomas Meyer );
176d7ffac33SThomas Meyer 
1771da177e4SLinus Torvalds static int __init Usage(char *line, int *add)
1781da177e4SLinus Torvalds {
1791da177e4SLinus Torvalds 	const char **p;
1801da177e4SLinus Torvalds 
18196b644bdSSerge E. Hallyn 	printf(usage_string, init_utsname()->release);
1821da177e4SLinus Torvalds 	p = &__uml_help_start;
1830936d4f3SMasami Hiramatsu 	/* Explicitly use printf() to show help in stdout */
1841da177e4SLinus Torvalds 	while (p < &__uml_help_end) {
1851da177e4SLinus Torvalds 		printf("%s", *p);
1861da177e4SLinus Torvalds 		p++;
1871da177e4SLinus Torvalds 	}
1881da177e4SLinus Torvalds 	exit(0);
1891da177e4SLinus Torvalds 	return 0;
1901da177e4SLinus Torvalds }
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds __uml_setup("--help", Usage,
1931da177e4SLinus Torvalds "--help\n"
1941da177e4SLinus Torvalds "    Prints this message.\n\n"
1951da177e4SLinus Torvalds );
1961da177e4SLinus Torvalds 
1976b7e9674SKarol Swietlicki static void __init uml_checksetup(char *line, int *add)
1981da177e4SLinus Torvalds {
1991da177e4SLinus Torvalds 	struct uml_param *p;
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds 	p = &__uml_setup_start;
2021da177e4SLinus Torvalds 	while (p < &__uml_setup_end) {
2033af9c5beSWANG Cong 		size_t n;
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds 		n = strlen(p->str);
206ba180fd4SJeff Dike 		if (!strncmp(line, p->str, n) && p->setup_func(line + n, add))
2076b7e9674SKarol Swietlicki 			return;
2081da177e4SLinus Torvalds 		p++;
2091da177e4SLinus Torvalds 	}
2101da177e4SLinus Torvalds }
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds static void __init uml_postsetup(void)
2131da177e4SLinus Torvalds {
2141da177e4SLinus Torvalds 	initcall_t *p;
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds 	p = &__uml_postsetup_start;
2171da177e4SLinus Torvalds 	while (p < &__uml_postsetup_end) {
2181da177e4SLinus Torvalds 		(*p)();
2191da177e4SLinus Torvalds 		p++;
2201da177e4SLinus Torvalds 	}
2211da177e4SLinus Torvalds 	return;
2221da177e4SLinus Torvalds }
2231da177e4SLinus Torvalds 
2240983a88bSJeff Dike static int panic_exit(struct notifier_block *self, unsigned long unused1,
2250983a88bSJeff Dike 		      void *unused2)
2260983a88bSJeff Dike {
22704a41849SThomas Meyer 	kmsg_dump(KMSG_DUMP_PANIC);
2280983a88bSJeff Dike 	bust_spinlocks(1);
2290983a88bSJeff Dike 	bust_spinlocks(0);
2300983a88bSJeff Dike 	uml_exitcode = 1;
2310983a88bSJeff Dike 	os_dump_core();
2320983a88bSJeff Dike 	return 0;
2330983a88bSJeff Dike }
2340983a88bSJeff Dike 
2350983a88bSJeff Dike static struct notifier_block panic_exit_notifier = {
2360983a88bSJeff Dike 	.notifier_call 		= panic_exit,
2370983a88bSJeff Dike 	.next 			= NULL,
2380983a88bSJeff Dike 	.priority 		= 0
2390983a88bSJeff Dike };
2400983a88bSJeff Dike 
24133bbc306SThomas Meyer void uml_finishsetup(void)
24233bbc306SThomas Meyer {
24333bbc306SThomas Meyer 	atomic_notifier_chain_register(&panic_notifier_list,
24433bbc306SThomas Meyer 				       &panic_exit_notifier);
24533bbc306SThomas Meyer 
24633bbc306SThomas Meyer 	uml_postsetup();
24733bbc306SThomas Meyer 
24833bbc306SThomas Meyer 	new_thread_handler();
24933bbc306SThomas Meyer }
25033bbc306SThomas Meyer 
2511da177e4SLinus Torvalds /* Set during early boot */
252*bfc58e2bSJohannes Berg unsigned long stub_start;
253536788feSJeff Dike unsigned long task_size;
254536788feSJeff Dike EXPORT_SYMBOL(task_size);
255536788feSJeff Dike 
256536788feSJeff Dike unsigned long host_task_size;
257536788feSJeff Dike 
2581da177e4SLinus Torvalds unsigned long brk_start;
2591da177e4SLinus Torvalds unsigned long end_iomem;
2601da177e4SLinus Torvalds EXPORT_SYMBOL(end_iomem);
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds #define MIN_VMALLOC (32 * 1024 * 1024)
2631da177e4SLinus Torvalds 
2647a3a06d0SAlon Bar-Lev int __init linux_main(int argc, char **argv)
2651da177e4SLinus Torvalds {
2661da177e4SLinus Torvalds 	unsigned long avail, diff;
2671da177e4SLinus Torvalds 	unsigned long virtmem_size, max_physmem;
26860a2988aSJeff Dike 	unsigned long stack;
2693af9c5beSWANG Cong 	unsigned int i;
2703af9c5beSWANG Cong 	int add;
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 	for (i = 1; i < argc; i++) {
273ba180fd4SJeff Dike 		if ((i == 1) && (argv[i][0] == ' '))
274ba180fd4SJeff Dike 			continue;
2751da177e4SLinus Torvalds 		add = 1;
2761da177e4SLinus Torvalds 		uml_checksetup(argv[i], &add);
2771da177e4SLinus Torvalds 		if (add)
2781da177e4SLinus Torvalds 			add_arg(argv[i]);
2791da177e4SLinus Torvalds 	}
2801da177e4SLinus Torvalds 	if (have_root == 0)
281d7ffac33SThomas Meyer 		add_arg(DEFAULT_COMMAND_LINE_ROOT);
282d7ffac33SThomas Meyer 
283d7ffac33SThomas Meyer 	if (have_console == 0)
284d7ffac33SThomas Meyer 		add_arg(DEFAULT_COMMAND_LINE_CONSOLE);
2851da177e4SLinus Torvalds 
28640fb16a3STom Spink 	host_task_size = os_get_top_address();
287*bfc58e2bSJohannes Berg 	/* reserve two pages for the stubs */
288*bfc58e2bSJohannes Berg 	host_task_size -= 2 * PAGE_SIZE;
289*bfc58e2bSJohannes Berg 	stub_start = host_task_size;
290*bfc58e2bSJohannes Berg 
291536788feSJeff Dike 	/*
292536788feSJeff Dike 	 * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps
293536788feSJeff Dike 	 * out
294536788feSJeff Dike 	 */
295536788feSJeff Dike 	task_size = host_task_size & PGDIR_MASK;
296536788feSJeff Dike 
297ba180fd4SJeff Dike 	/* OS sanity checks that need to happen before the kernel runs */
29860d339f6SGennady Sharapov 	os_early_checks();
299cb66504dSPaolo 'Blaisorblade' Giarrusso 
3001da177e4SLinus Torvalds 	brk_start = (unsigned long) sbrk(0);
30177bf4400SJeff Dike 
302ba180fd4SJeff Dike 	/*
303ba180fd4SJeff Dike 	 * Increase physical memory size for exec-shield users
304ba180fd4SJeff Dike 	 * so they actually get what they asked for. This should
305ba180fd4SJeff Dike 	 * add zero for non-exec shield users
306ba180fd4SJeff Dike 	 */
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds 	diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
3091da177e4SLinus Torvalds 	if (diff > 1024 * 1024) {
310d3878bb8SMasami Hiramatsu 		os_info("Adding %ld bytes to physical memory to account for "
3111da177e4SLinus Torvalds 			"exec-shield gap\n", diff);
3121da177e4SLinus Torvalds 		physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
3131da177e4SLinus Torvalds 	}
3141da177e4SLinus Torvalds 
31505eacfd0SNicolas Iooss 	uml_physmem = (unsigned long) __binary_start & PAGE_MASK;
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds 	/* Reserve up to 4M after the current brk */
3181da177e4SLinus Torvalds 	uml_reserved = ROUND_4M(brk_start) + (1 << 22);
3191da177e4SLinus Torvalds 
32096b644bdSSerge E. Hallyn 	setup_machinename(init_utsname()->machine);
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds 	highmem = 0;
3231da177e4SLinus Torvalds 	iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
324536788feSJeff Dike 	max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC;
3251da177e4SLinus Torvalds 
326ba180fd4SJeff Dike 	/*
327ba180fd4SJeff Dike 	 * Zones have to begin on a 1 << MAX_ORDER page boundary,
3281da177e4SLinus Torvalds 	 * so this makes sure that's true for highmem
3291da177e4SLinus Torvalds 	 */
3301da177e4SLinus Torvalds 	max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
3311da177e4SLinus Torvalds 	if (physmem_size + iomem_size > max_physmem) {
3321da177e4SLinus Torvalds 		highmem = physmem_size + iomem_size - max_physmem;
3331da177e4SLinus Torvalds 		physmem_size -= highmem;
3341da177e4SLinus Torvalds 	}
3351da177e4SLinus Torvalds 
3361da177e4SLinus Torvalds 	high_physmem = uml_physmem + physmem_size;
3371da177e4SLinus Torvalds 	end_iomem = high_physmem + iomem_size;
3381da177e4SLinus Torvalds 	high_memory = (void *) end_iomem;
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 	start_vm = VMALLOC_START;
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds 	virtmem_size = physmem_size;
34360a2988aSJeff Dike 	stack = (unsigned long) argv;
34460a2988aSJeff Dike 	stack &= ~(1024 * 1024 - 1);
34560a2988aSJeff Dike 	avail = stack - start_vm;
346ba180fd4SJeff Dike 	if (physmem_size > avail)
347ba180fd4SJeff Dike 		virtmem_size = avail;
3481da177e4SLinus Torvalds 	end_vm = start_vm + virtmem_size;
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds 	if (virtmem_size < physmem_size)
351d3878bb8SMasami Hiramatsu 		os_info("Kernel virtual memory size shrunk to %lu bytes\n",
3521da177e4SLinus Torvalds 			virtmem_size);
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 	os_flush_stdout();
3551da177e4SLinus Torvalds 
35677bf4400SJeff Dike 	return start_uml();
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds 
3595b4236e1SMasami Hiramatsu int __init __weak read_initrd(void)
3605b4236e1SMasami Hiramatsu {
3615b4236e1SMasami Hiramatsu 	return 0;
3625b4236e1SMasami Hiramatsu }
3635b4236e1SMasami Hiramatsu 
3641da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p)
3651da177e4SLinus Torvalds {
366b6323697SRichard Weinberger 	stack_protections((unsigned long) &init_thread_info);
367b6323697SRichard Weinberger 	setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
368b6323697SRichard Weinberger 	mem_total_pages(physmem_size, iomem_size, highmem);
3695b4236e1SMasami Hiramatsu 	read_initrd();
370b6323697SRichard Weinberger 
3711da177e4SLinus Torvalds 	paging_init();
37219bf7e7aSAlon Bar-Lev 	strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
3731da177e4SLinus Torvalds 	*cmdline_p = command_line;
374b4ffb6adSJeff Dike 	setup_hostinfo(host_info, sizeof host_info);
3751da177e4SLinus Torvalds }
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds void __init check_bugs(void)
3781da177e4SLinus Torvalds {
3791da177e4SLinus Torvalds 	arch_check_bugs();
3808e367065SJeff Dike 	os_check_bugs();
3811da177e4SLinus Torvalds }
3821da177e4SLinus Torvalds 
3839a0b5817SGerd Hoffmann void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
3849a0b5817SGerd Hoffmann {
3859a0b5817SGerd Hoffmann }
38688fc078aSPeter Zijlstra 
38788fc078aSPeter Zijlstra void *text_poke(void *addr, const void *opcode, size_t len)
38888fc078aSPeter Zijlstra {
38988fc078aSPeter Zijlstra 	/*
39088fc078aSPeter Zijlstra 	 * In UML, the only reference to this function is in
39188fc078aSPeter Zijlstra 	 * apply_relocate_add(), which shouldn't ever actually call this
39288fc078aSPeter Zijlstra 	 * because UML doesn't have live patching.
39388fc078aSPeter Zijlstra 	 */
39488fc078aSPeter Zijlstra 	WARN_ON(1);
39588fc078aSPeter Zijlstra 
39688fc078aSPeter Zijlstra 	return memcpy(addr, opcode, len);
39788fc078aSPeter Zijlstra }
39888fc078aSPeter Zijlstra 
39988fc078aSPeter Zijlstra void text_poke_sync(void)
40088fc078aSPeter Zijlstra {
40188fc078aSPeter Zijlstra }
40292dcd3d3SJohannes Berg 
40392dcd3d3SJohannes Berg void uml_pm_wake(void)
40492dcd3d3SJohannes Berg {
40592dcd3d3SJohannes Berg 	pm_system_wakeup();
40692dcd3d3SJohannes Berg }
40792dcd3d3SJohannes Berg 
4081fb1abc8SJohannes Berg #ifdef CONFIG_PM_SLEEP
409a374b7cbSJohannes Berg static int um_suspend_valid(suspend_state_t state)
410a374b7cbSJohannes Berg {
411a374b7cbSJohannes Berg 	return state == PM_SUSPEND_MEM;
412a374b7cbSJohannes Berg }
413a374b7cbSJohannes Berg 
414a374b7cbSJohannes Berg static int um_suspend_prepare(void)
415a374b7cbSJohannes Berg {
416a374b7cbSJohannes Berg 	um_irqs_suspend();
417a374b7cbSJohannes Berg 	return 0;
418a374b7cbSJohannes Berg }
419a374b7cbSJohannes Berg 
420a374b7cbSJohannes Berg static int um_suspend_enter(suspend_state_t state)
421a374b7cbSJohannes Berg {
422a374b7cbSJohannes Berg 	if (WARN_ON(state != PM_SUSPEND_MEM))
423a374b7cbSJohannes Berg 		return -EINVAL;
424a374b7cbSJohannes Berg 
425a374b7cbSJohannes Berg 	/*
426a374b7cbSJohannes Berg 	 * This is identical to the idle sleep, but we've just
427a374b7cbSJohannes Berg 	 * (during suspend) turned off all interrupt sources
428a374b7cbSJohannes Berg 	 * except for the ones we want, so now we can only wake
429a374b7cbSJohannes Berg 	 * up on something we actually want to wake up on. All
430a374b7cbSJohannes Berg 	 * timing has also been suspended.
431a374b7cbSJohannes Berg 	 */
432a374b7cbSJohannes Berg 	um_idle_sleep();
433a374b7cbSJohannes Berg 	return 0;
434a374b7cbSJohannes Berg }
435a374b7cbSJohannes Berg 
436a374b7cbSJohannes Berg static void um_suspend_finish(void)
437a374b7cbSJohannes Berg {
438a374b7cbSJohannes Berg 	um_irqs_resume();
439a374b7cbSJohannes Berg }
440a374b7cbSJohannes Berg 
441a374b7cbSJohannes Berg const struct platform_suspend_ops um_suspend_ops = {
442a374b7cbSJohannes Berg 	.valid = um_suspend_valid,
443a374b7cbSJohannes Berg 	.prepare = um_suspend_prepare,
444a374b7cbSJohannes Berg 	.enter = um_suspend_enter,
445a374b7cbSJohannes Berg 	.finish = um_suspend_finish,
446a374b7cbSJohannes Berg };
447a374b7cbSJohannes Berg 
44892dcd3d3SJohannes Berg static int init_pm_wake_signal(void)
44992dcd3d3SJohannes Berg {
45092dcd3d3SJohannes Berg 	/*
45192dcd3d3SJohannes Berg 	 * In external time-travel mode we can't use signals to wake up
45292dcd3d3SJohannes Berg 	 * since that would mess with the scheduling. We'll have to do
45392dcd3d3SJohannes Berg 	 * some additional work to support wakeup on virtio devices or
45492dcd3d3SJohannes Berg 	 * similar, perhaps implementing a fake RTC controller that can
45592dcd3d3SJohannes Berg 	 * trigger wakeup (and request the appropriate scheduling from
45692dcd3d3SJohannes Berg 	 * the external scheduler when going to suspend.)
45792dcd3d3SJohannes Berg 	 */
45892dcd3d3SJohannes Berg 	if (time_travel_mode != TT_MODE_EXTERNAL)
45992dcd3d3SJohannes Berg 		register_pm_wake_signal();
460a374b7cbSJohannes Berg 
461a374b7cbSJohannes Berg 	suspend_set_ops(&um_suspend_ops);
462a374b7cbSJohannes Berg 
46392dcd3d3SJohannes Berg 	return 0;
46492dcd3d3SJohannes Berg }
46592dcd3d3SJohannes Berg 
46692dcd3d3SJohannes Berg late_initcall(init_pm_wake_signal);
46792dcd3d3SJohannes Berg #endif
468