xref: /openbmc/linux/arch/um/os-Linux/util.c (revision 87832e937c808a7ebc41254b408362e3255c87c9)
197870c34SAlex Dewar // SPDX-License-Identifier: GPL-2.0
24fef0c10SGennady Sharapov /*
35134d8feSJeff Dike  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
44fef0c10SGennady Sharapov  */
54fef0c10SGennady Sharapov 
639f75da7SAlexey Dobriyan #include <stdarg.h>
74fef0c10SGennady Sharapov #include <stdio.h>
84fef0c10SGennady Sharapov #include <stdlib.h>
9b2db2199SRichard Weinberger #include <unistd.h>
104fef0c10SGennady Sharapov #include <errno.h>
115134d8feSJeff Dike #include <signal.h>
124fef0c10SGennady Sharapov #include <string.h>
135134d8feSJeff Dike #include <termios.h>
145e1121cdSIgnat Korchagin #include <sys/wait.h>
155134d8feSJeff Dike #include <sys/mman.h>
165134d8feSJeff Dike #include <sys/utsname.h>
170b9ba613SJason A. Donenfeld #include <sys/random.h>
18f7887ee1SMasami Hiramatsu #include <init.h>
1937185b33SAl Viro #include <os.h>
204fef0c10SGennady Sharapov 
stack_protections(unsigned long address)214fef0c10SGennady Sharapov void stack_protections(unsigned long address)
224fef0c10SGennady Sharapov {
2357598fd7SJeff Dike 	if (mprotect((void *) address, UM_THREAD_SIZE,
2457598fd7SJeff Dike 		    PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
254fef0c10SGennady Sharapov 		panic("protecting stack failed, errno = %d", errno);
264fef0c10SGennady Sharapov }
274fef0c10SGennady Sharapov 
raw(int fd)284fef0c10SGennady Sharapov int raw(int fd)
294fef0c10SGennady Sharapov {
304fef0c10SGennady Sharapov 	struct termios tt;
314fef0c10SGennady Sharapov 	int err;
324fef0c10SGennady Sharapov 
334fef0c10SGennady Sharapov 	CATCH_EINTR(err = tcgetattr(fd, &tt));
344fef0c10SGennady Sharapov 	if (err < 0)
354fef0c10SGennady Sharapov 		return -errno;
364fef0c10SGennady Sharapov 
374fef0c10SGennady Sharapov 	cfmakeraw(&tt);
384fef0c10SGennady Sharapov 
394fef0c10SGennady Sharapov 	CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt));
404fef0c10SGennady Sharapov 	if (err < 0)
414fef0c10SGennady Sharapov 		return -errno;
424fef0c10SGennady Sharapov 
435134d8feSJeff Dike 	/*
445134d8feSJeff Dike 	 * XXX tcsetattr could have applied only some changes
455134d8feSJeff Dike 	 * (and cfmakeraw() is a set of changes)
465134d8feSJeff Dike 	 */
4757598fd7SJeff Dike 	return 0;
484fef0c10SGennady Sharapov }
494fef0c10SGennady Sharapov 
setup_machinename(char * machine_out)504fef0c10SGennady Sharapov void setup_machinename(char *machine_out)
514fef0c10SGennady Sharapov {
524fef0c10SGennady Sharapov 	struct utsname host;
534fef0c10SGennady Sharapov 
544fef0c10SGennady Sharapov 	uname(&host);
5569fada32SPaolo 'Blaisorblade' Giarrusso #ifdef UML_CONFIG_UML_X86
5669fada32SPaolo 'Blaisorblade' Giarrusso # ifndef UML_CONFIG_64BIT
574fef0c10SGennady Sharapov 	if (!strcmp(host.machine, "x86_64")) {
584fef0c10SGennady Sharapov 		strcpy(machine_out, "i686");
594fef0c10SGennady Sharapov 		return;
604fef0c10SGennady Sharapov 	}
6169fada32SPaolo 'Blaisorblade' Giarrusso # else
6269fada32SPaolo 'Blaisorblade' Giarrusso 	if (!strcmp(host.machine, "i686")) {
6369fada32SPaolo 'Blaisorblade' Giarrusso 		strcpy(machine_out, "x86_64");
6469fada32SPaolo 'Blaisorblade' Giarrusso 		return;
6569fada32SPaolo 'Blaisorblade' Giarrusso 	}
6669fada32SPaolo 'Blaisorblade' Giarrusso # endif
674fef0c10SGennady Sharapov #endif
684fef0c10SGennady Sharapov 	strcpy(machine_out, host.machine);
694fef0c10SGennady Sharapov }
704fef0c10SGennady Sharapov 
setup_hostinfo(char * buf,int len)71b4ffb6adSJeff Dike void setup_hostinfo(char *buf, int len)
724fef0c10SGennady Sharapov {
734fef0c10SGennady Sharapov 	struct utsname host;
744fef0c10SGennady Sharapov 
754fef0c10SGennady Sharapov 	uname(&host);
76b4ffb6adSJeff Dike 	snprintf(buf, len, "%s %s %s %s %s", host.sysname, host.nodename,
774fef0c10SGennady Sharapov 		 host.release, host.version, host.machine);
784fef0c10SGennady Sharapov }
794fef0c10SGennady Sharapov 
80b2db2199SRichard Weinberger /*
81b2db2199SRichard Weinberger  * We cannot use glibc's abort(). It makes use of tgkill() which
82b2db2199SRichard Weinberger  * has no effect within UML's kernel threads.
83b2db2199SRichard Weinberger  * After that glibc would execute an invalid instruction to kill
84b2db2199SRichard Weinberger  * the calling process and UML crashes with SIGSEGV.
85b2db2199SRichard Weinberger  */
uml_abort(void)86b2db2199SRichard Weinberger static inline void __attribute__ ((noreturn)) uml_abort(void)
87b2db2199SRichard Weinberger {
88b2db2199SRichard Weinberger 	sigset_t sig;
89b2db2199SRichard Weinberger 
90b2db2199SRichard Weinberger 	fflush(NULL);
91b2db2199SRichard Weinberger 
92b2db2199SRichard Weinberger 	if (!sigemptyset(&sig) && !sigaddset(&sig, SIGABRT))
93b2db2199SRichard Weinberger 		sigprocmask(SIG_UNBLOCK, &sig, 0);
94b2db2199SRichard Weinberger 
95b2db2199SRichard Weinberger 	for (;;)
96b2db2199SRichard Weinberger 		if (kill(getpid(), SIGABRT) < 0)
97b2db2199SRichard Weinberger 			exit(127);
98b2db2199SRichard Weinberger }
99b2db2199SRichard Weinberger 
os_getrandom(void * buf,size_t len,unsigned int flags)1000b9ba613SJason A. Donenfeld ssize_t os_getrandom(void *buf, size_t len, unsigned int flags)
1010b9ba613SJason A. Donenfeld {
1020b9ba613SJason A. Donenfeld 	return getrandom(buf, len, flags);
1030b9ba613SJason A. Donenfeld }
1040b9ba613SJason A. Donenfeld 
10591d44ff8SRichard Weinberger /*
10691d44ff8SRichard Weinberger  * UML helper threads must not handle SIGWINCH/INT/TERM
10791d44ff8SRichard Weinberger  */
os_fix_helper_signals(void)10891d44ff8SRichard Weinberger void os_fix_helper_signals(void)
10991d44ff8SRichard Weinberger {
11091d44ff8SRichard Weinberger 	signal(SIGWINCH, SIG_IGN);
11191d44ff8SRichard Weinberger 	signal(SIGINT, SIG_DFL);
11291d44ff8SRichard Weinberger 	signal(SIGTERM, SIG_DFL);
11391d44ff8SRichard Weinberger }
11491d44ff8SRichard Weinberger 
os_dump_core(void)11563843c26SJeff Dike void os_dump_core(void)
11663843c26SJeff Dike {
117a24864a1SLepton Wu 	int pid;
118a24864a1SLepton Wu 
11963843c26SJeff Dike 	signal(SIGSEGV, SIG_DFL);
120a24864a1SLepton Wu 
121a24864a1SLepton Wu 	/*
122a24864a1SLepton Wu 	 * We are about to SIGTERM this entire process group to ensure that
123a24864a1SLepton Wu 	 * nothing is around to run after the kernel exits.  The
124a24864a1SLepton Wu 	 * kernel wants to abort, not die through SIGTERM, so we
125a24864a1SLepton Wu 	 * ignore it here.
126a24864a1SLepton Wu 	 */
127a24864a1SLepton Wu 
128a24864a1SLepton Wu 	signal(SIGTERM, SIG_IGN);
129a24864a1SLepton Wu 	kill(0, SIGTERM);
130a24864a1SLepton Wu 	/*
131a24864a1SLepton Wu 	 * Most of the other processes associated with this UML are
132a24864a1SLepton Wu 	 * likely sTopped, so give them a SIGCONT so they see the
133a24864a1SLepton Wu 	 * SIGTERM.
134a24864a1SLepton Wu 	 */
135a24864a1SLepton Wu 	kill(0, SIGCONT);
136a24864a1SLepton Wu 
137a24864a1SLepton Wu 	/*
138a24864a1SLepton Wu 	 * Now, having sent signals to everyone but us, make sure they
139a24864a1SLepton Wu 	 * die by ptrace.  Processes can survive what's been done to
140a24864a1SLepton Wu 	 * them so far - the mechanism I understand is receiving a
141a24864a1SLepton Wu 	 * SIGSEGV and segfaulting immediately upon return.  There is
142a24864a1SLepton Wu 	 * always a SIGSEGV pending, and (I'm guessing) signals are
143a24864a1SLepton Wu 	 * processed in numeric order so the SIGTERM (signal 15 vs
144a24864a1SLepton Wu 	 * SIGSEGV being signal 11) is never handled.
145a24864a1SLepton Wu 	 *
146a24864a1SLepton Wu 	 * Run a waitpid loop until we get some kind of error.
147a24864a1SLepton Wu 	 * Hopefully, it's ECHILD, but there's not a lot we can do if
148a24864a1SLepton Wu 	 * it's something else.  Tell os_kill_ptraced_process not to
149a24864a1SLepton Wu 	 * wait for the child to report its death because there's
150a24864a1SLepton Wu 	 * nothing reasonable to do if that fails.
151a24864a1SLepton Wu 	 */
152a24864a1SLepton Wu 
1534dbed85aSStanislaw Gruszka 	while ((pid = waitpid(-1, NULL, WNOHANG | __WALL)) > 0)
154a24864a1SLepton Wu 		os_kill_ptraced_process(pid, 0);
155a24864a1SLepton Wu 
156b2db2199SRichard Weinberger 	uml_abort();
15763843c26SJeff Dike }
158d634f194SRichard Weinberger 
um_early_printk(const char * s,unsigned int n)159d634f194SRichard Weinberger void um_early_printk(const char *s, unsigned int n)
160d634f194SRichard Weinberger {
161d634f194SRichard Weinberger 	printf("%.*s", n, s);
162d634f194SRichard Weinberger }
163f7887ee1SMasami Hiramatsu 
164f7887ee1SMasami Hiramatsu static int quiet_info;
165f7887ee1SMasami Hiramatsu 
quiet_cmd_param(char * str,int * add)166f7887ee1SMasami Hiramatsu static int __init quiet_cmd_param(char *str, int *add)
167f7887ee1SMasami Hiramatsu {
168f7887ee1SMasami Hiramatsu 	quiet_info = 1;
169f7887ee1SMasami Hiramatsu 	return 0;
170f7887ee1SMasami Hiramatsu }
171f7887ee1SMasami Hiramatsu 
172f7887ee1SMasami Hiramatsu __uml_setup("quiet", quiet_cmd_param,
173f7887ee1SMasami Hiramatsu "quiet\n"
174f7887ee1SMasami Hiramatsu "    Turns off information messages during boot.\n\n");
175f7887ee1SMasami Hiramatsu 
176*a4378abcSBenjamin Berg /*
177*a4378abcSBenjamin Berg  * The os_info/os_warn functions will be called by helper threads. These
178*a4378abcSBenjamin Berg  * have a very limited stack size and using the libc formatting functions
179*a4378abcSBenjamin Berg  * may overflow the stack.
180*a4378abcSBenjamin Berg  * So pull in the kernel vscnprintf and use that instead with a fixed
181*a4378abcSBenjamin Berg  * on-stack buffer.
182*a4378abcSBenjamin Berg  */
183*a4378abcSBenjamin Berg int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
184*a4378abcSBenjamin Berg 
os_info(const char * fmt,...)185f7887ee1SMasami Hiramatsu void os_info(const char *fmt, ...)
186f7887ee1SMasami Hiramatsu {
187*a4378abcSBenjamin Berg 	char buf[256];
188f7887ee1SMasami Hiramatsu 	va_list list;
189*a4378abcSBenjamin Berg 	int len;
190f7887ee1SMasami Hiramatsu 
191f7887ee1SMasami Hiramatsu 	if (quiet_info)
192f7887ee1SMasami Hiramatsu 		return;
193f7887ee1SMasami Hiramatsu 
194f7887ee1SMasami Hiramatsu 	va_start(list, fmt);
195*a4378abcSBenjamin Berg 	len = vscnprintf(buf, sizeof(buf), fmt, list);
196*a4378abcSBenjamin Berg 	fwrite(buf, len, 1, stderr);
197f7887ee1SMasami Hiramatsu 	va_end(list);
198f7887ee1SMasami Hiramatsu }
199721ccae8SMasami Hiramatsu 
os_warn(const char * fmt,...)200721ccae8SMasami Hiramatsu void os_warn(const char *fmt, ...)
201721ccae8SMasami Hiramatsu {
202*a4378abcSBenjamin Berg 	char buf[256];
203721ccae8SMasami Hiramatsu 	va_list list;
204*a4378abcSBenjamin Berg 	int len;
205721ccae8SMasami Hiramatsu 
206721ccae8SMasami Hiramatsu 	va_start(list, fmt);
207*a4378abcSBenjamin Berg 	len = vscnprintf(buf, sizeof(buf), fmt, list);
208*a4378abcSBenjamin Berg 	fwrite(buf, len, 1, stderr);
209721ccae8SMasami Hiramatsu 	va_end(list);
210721ccae8SMasami Hiramatsu }
211