18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <stdio.h>
78c2ecf20Sopenharmony_ci#include <stdlib.h>
88c2ecf20Sopenharmony_ci#include <stdarg.h>
98c2ecf20Sopenharmony_ci#include <unistd.h>
108c2ecf20Sopenharmony_ci#include <errno.h>
118c2ecf20Sopenharmony_ci#include <fcntl.h>
128c2ecf20Sopenharmony_ci#include <sched.h>
138c2ecf20Sopenharmony_ci#include <signal.h>
148c2ecf20Sopenharmony_ci#include <string.h>
158c2ecf20Sopenharmony_ci#include <sys/mman.h>
168c2ecf20Sopenharmony_ci#include <sys/stat.h>
178c2ecf20Sopenharmony_ci#include <sys/wait.h>
188c2ecf20Sopenharmony_ci#include <sys/time.h>
198c2ecf20Sopenharmony_ci#include <sys/resource.h>
208c2ecf20Sopenharmony_ci#include <asm/unistd.h>
218c2ecf20Sopenharmony_ci#include <init.h>
228c2ecf20Sopenharmony_ci#include <os.h>
238c2ecf20Sopenharmony_ci#include <mem_user.h>
248c2ecf20Sopenharmony_ci#include <ptrace_user.h>
258c2ecf20Sopenharmony_ci#include <registers.h>
268c2ecf20Sopenharmony_ci#include <skas.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic void ptrace_child(void)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	int ret;
318c2ecf20Sopenharmony_ci	/* Calling os_getpid because some libcs cached getpid incorrectly */
328c2ecf20Sopenharmony_ci	int pid = os_getpid(), ppid = getppid();
338c2ecf20Sopenharmony_ci	int sc_result;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	if (change_sig(SIGWINCH, 0) < 0 ||
368c2ecf20Sopenharmony_ci	    ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
378c2ecf20Sopenharmony_ci		perror("ptrace");
388c2ecf20Sopenharmony_ci		kill(pid, SIGKILL);
398c2ecf20Sopenharmony_ci	}
408c2ecf20Sopenharmony_ci	kill(pid, SIGSTOP);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	/*
438c2ecf20Sopenharmony_ci	 * This syscall will be intercepted by the parent. Don't call more than
448c2ecf20Sopenharmony_ci	 * once, please.
458c2ecf20Sopenharmony_ci	 */
468c2ecf20Sopenharmony_ci	sc_result = os_getpid();
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	if (sc_result == pid)
498c2ecf20Sopenharmony_ci		/* Nothing modified by the parent, we are running normally. */
508c2ecf20Sopenharmony_ci		ret = 1;
518c2ecf20Sopenharmony_ci	else if (sc_result == ppid)
528c2ecf20Sopenharmony_ci		/*
538c2ecf20Sopenharmony_ci		 * Expected in check_ptrace and check_sysemu when they succeed
548c2ecf20Sopenharmony_ci		 * in modifying the stack frame
558c2ecf20Sopenharmony_ci		 */
568c2ecf20Sopenharmony_ci		ret = 0;
578c2ecf20Sopenharmony_ci	else
588c2ecf20Sopenharmony_ci		/* Serious trouble! This could be caused by a bug in host 2.6
598c2ecf20Sopenharmony_ci		 * SKAS3/2.6 patch before release -V6, together with a bug in
608c2ecf20Sopenharmony_ci		 * the UML code itself.
618c2ecf20Sopenharmony_ci		 */
628c2ecf20Sopenharmony_ci		ret = 2;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	exit(ret);
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic void fatal_perror(const char *str)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	perror(str);
708c2ecf20Sopenharmony_ci	exit(1);
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic void fatal(char *fmt, ...)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	va_list list;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	va_start(list, fmt);
788c2ecf20Sopenharmony_ci	vfprintf(stderr, fmt, list);
798c2ecf20Sopenharmony_ci	va_end(list);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	exit(1);
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic void non_fatal(char *fmt, ...)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	va_list list;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	va_start(list, fmt);
898c2ecf20Sopenharmony_ci	vfprintf(stderr, fmt, list);
908c2ecf20Sopenharmony_ci	va_end(list);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic int start_ptraced_child(void)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	int pid, n, status;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	fflush(stdout);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	pid = fork();
1008c2ecf20Sopenharmony_ci	if (pid == 0)
1018c2ecf20Sopenharmony_ci		ptrace_child();
1028c2ecf20Sopenharmony_ci	else if (pid < 0)
1038c2ecf20Sopenharmony_ci		fatal_perror("start_ptraced_child : fork failed");
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
1068c2ecf20Sopenharmony_ci	if (n < 0)
1078c2ecf20Sopenharmony_ci		fatal_perror("check_ptrace : waitpid failed");
1088c2ecf20Sopenharmony_ci	if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
1098c2ecf20Sopenharmony_ci		fatal("check_ptrace : expected SIGSTOP, got status = %d",
1108c2ecf20Sopenharmony_ci		      status);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	return pid;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/* When testing for SYSEMU support, if it is one of the broken versions, we
1168c2ecf20Sopenharmony_ci * must just avoid using sysemu, not panic, but only if SYSEMU features are
1178c2ecf20Sopenharmony_ci * broken.
1188c2ecf20Sopenharmony_ci * So only for SYSEMU features we test mustpanic, while normal host features
1198c2ecf20Sopenharmony_ci * must work anyway!
1208c2ecf20Sopenharmony_ci */
1218c2ecf20Sopenharmony_cistatic int stop_ptraced_child(int pid, int exitcode, int mustexit)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	int status, n, ret = 0;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) {
1268c2ecf20Sopenharmony_ci		perror("stop_ptraced_child : ptrace failed");
1278c2ecf20Sopenharmony_ci		return -1;
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci	CATCH_EINTR(n = waitpid(pid, &status, 0));
1308c2ecf20Sopenharmony_ci	if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
1318c2ecf20Sopenharmony_ci		int exit_with = WEXITSTATUS(status);
1328c2ecf20Sopenharmony_ci		if (exit_with == 2)
1338c2ecf20Sopenharmony_ci			non_fatal("check_ptrace : child exited with status 2. "
1348c2ecf20Sopenharmony_ci				  "\nDisabling SYSEMU support.\n");
1358c2ecf20Sopenharmony_ci		non_fatal("check_ptrace : child exited with exitcode %d, while "
1368c2ecf20Sopenharmony_ci			  "expecting %d; status 0x%x\n", exit_with,
1378c2ecf20Sopenharmony_ci			  exitcode, status);
1388c2ecf20Sopenharmony_ci		if (mustexit)
1398c2ecf20Sopenharmony_ci			exit(1);
1408c2ecf20Sopenharmony_ci		ret = -1;
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	return ret;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci/* Changed only during early boot */
1478c2ecf20Sopenharmony_cistatic int force_sysemu_disabled = 0;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic int __init nosysemu_cmd_param(char *str, int* add)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	force_sysemu_disabled = 1;
1528c2ecf20Sopenharmony_ci	return 0;
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci__uml_setup("nosysemu", nosysemu_cmd_param,
1568c2ecf20Sopenharmony_ci"nosysemu\n"
1578c2ecf20Sopenharmony_ci"    Turns off syscall emulation patch for ptrace (SYSEMU).\n"
1588c2ecf20Sopenharmony_ci"    SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
1598c2ecf20Sopenharmony_ci"    behaviour of ptrace() and helps reduce host context switch rates.\n"
1608c2ecf20Sopenharmony_ci"    To make it work, you need a kernel patch for your host, too.\n"
1618c2ecf20Sopenharmony_ci"    See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n"
1628c2ecf20Sopenharmony_ci"    information.\n\n");
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic void __init check_sysemu(void)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	unsigned long regs[MAX_REG_NR];
1678c2ecf20Sopenharmony_ci	int pid, n, status, count=0;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	os_info("Checking syscall emulation patch for ptrace...");
1708c2ecf20Sopenharmony_ci	sysemu_supported = 0;
1718c2ecf20Sopenharmony_ci	pid = start_ptraced_child();
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
1748c2ecf20Sopenharmony_ci		goto fail;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
1778c2ecf20Sopenharmony_ci	if (n < 0)
1788c2ecf20Sopenharmony_ci		fatal_perror("check_sysemu : wait failed");
1798c2ecf20Sopenharmony_ci	if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
1808c2ecf20Sopenharmony_ci		fatal("check_sysemu : expected SIGTRAP, got status = %d\n",
1818c2ecf20Sopenharmony_ci		      status);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
1848c2ecf20Sopenharmony_ci		fatal_perror("check_sysemu : PTRACE_GETREGS failed");
1858c2ecf20Sopenharmony_ci	if (PT_SYSCALL_NR(regs) != __NR_getpid) {
1868c2ecf20Sopenharmony_ci		non_fatal("check_sysemu got system call number %d, "
1878c2ecf20Sopenharmony_ci			  "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid);
1888c2ecf20Sopenharmony_ci		goto fail;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid());
1928c2ecf20Sopenharmony_ci	if (n < 0) {
1938c2ecf20Sopenharmony_ci		non_fatal("check_sysemu : failed to modify system call "
1948c2ecf20Sopenharmony_ci			  "return");
1958c2ecf20Sopenharmony_ci		goto fail;
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (stop_ptraced_child(pid, 0, 0) < 0)
1998c2ecf20Sopenharmony_ci		goto fail_stopped;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	sysemu_supported = 1;
2028c2ecf20Sopenharmony_ci	os_info("OK\n");
2038c2ecf20Sopenharmony_ci	set_using_sysemu(!force_sysemu_disabled);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	os_info("Checking advanced syscall emulation patch for ptrace...");
2068c2ecf20Sopenharmony_ci	pid = start_ptraced_child();
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
2098c2ecf20Sopenharmony_ci		   (void *) PTRACE_O_TRACESYSGOOD) < 0))
2108c2ecf20Sopenharmony_ci		fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed");
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	while (1) {
2138c2ecf20Sopenharmony_ci		count++;
2148c2ecf20Sopenharmony_ci		if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
2158c2ecf20Sopenharmony_ci			goto fail;
2168c2ecf20Sopenharmony_ci		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
2178c2ecf20Sopenharmony_ci		if (n < 0)
2188c2ecf20Sopenharmony_ci			fatal_perror("check_sysemu: wait failed");
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci		if (WIFSTOPPED(status) &&
2218c2ecf20Sopenharmony_ci		    (WSTOPSIG(status) == (SIGTRAP|0x80))) {
2228c2ecf20Sopenharmony_ci			if (!count) {
2238c2ecf20Sopenharmony_ci				non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
2248c2ecf20Sopenharmony_ci					  "doesn't singlestep");
2258c2ecf20Sopenharmony_ci				goto fail;
2268c2ecf20Sopenharmony_ci			}
2278c2ecf20Sopenharmony_ci			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
2288c2ecf20Sopenharmony_ci				   os_getpid());
2298c2ecf20Sopenharmony_ci			if (n < 0)
2308c2ecf20Sopenharmony_ci				fatal_perror("check_sysemu : failed to modify "
2318c2ecf20Sopenharmony_ci					     "system call return");
2328c2ecf20Sopenharmony_ci			break;
2338c2ecf20Sopenharmony_ci		}
2348c2ecf20Sopenharmony_ci		else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
2358c2ecf20Sopenharmony_ci			count++;
2368c2ecf20Sopenharmony_ci		else {
2378c2ecf20Sopenharmony_ci			non_fatal("check_sysemu: expected SIGTRAP or "
2388c2ecf20Sopenharmony_ci				  "(SIGTRAP | 0x80), got status = %d\n",
2398c2ecf20Sopenharmony_ci				  status);
2408c2ecf20Sopenharmony_ci			goto fail;
2418c2ecf20Sopenharmony_ci		}
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci	if (stop_ptraced_child(pid, 0, 0) < 0)
2448c2ecf20Sopenharmony_ci		goto fail_stopped;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	sysemu_supported = 2;
2478c2ecf20Sopenharmony_ci	os_info("OK\n");
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (!force_sysemu_disabled)
2508c2ecf20Sopenharmony_ci		set_using_sysemu(sysemu_supported);
2518c2ecf20Sopenharmony_ci	return;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cifail:
2548c2ecf20Sopenharmony_ci	stop_ptraced_child(pid, 1, 0);
2558c2ecf20Sopenharmony_cifail_stopped:
2568c2ecf20Sopenharmony_ci	non_fatal("missing\n");
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic void __init check_ptrace(void)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	int pid, syscall, n, status;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	os_info("Checking that ptrace can change system call numbers...");
2648c2ecf20Sopenharmony_ci	pid = start_ptraced_child();
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
2678c2ecf20Sopenharmony_ci		   (void *) PTRACE_O_TRACESYSGOOD) < 0))
2688c2ecf20Sopenharmony_ci		fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed");
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	while (1) {
2718c2ecf20Sopenharmony_ci		if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
2728c2ecf20Sopenharmony_ci			fatal_perror("check_ptrace : ptrace failed");
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
2758c2ecf20Sopenharmony_ci		if (n < 0)
2768c2ecf20Sopenharmony_ci			fatal_perror("check_ptrace : wait failed");
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci		if (!WIFSTOPPED(status) ||
2798c2ecf20Sopenharmony_ci		   (WSTOPSIG(status) != (SIGTRAP | 0x80)))
2808c2ecf20Sopenharmony_ci			fatal("check_ptrace : expected (SIGTRAP|0x80), "
2818c2ecf20Sopenharmony_ci			       "got status = %d", status);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci		syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
2848c2ecf20Sopenharmony_ci				 0);
2858c2ecf20Sopenharmony_ci		if (syscall == __NR_getpid) {
2868c2ecf20Sopenharmony_ci			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
2878c2ecf20Sopenharmony_ci				   __NR_getppid);
2888c2ecf20Sopenharmony_ci			if (n < 0)
2898c2ecf20Sopenharmony_ci				fatal_perror("check_ptrace : failed to modify "
2908c2ecf20Sopenharmony_ci					     "system call");
2918c2ecf20Sopenharmony_ci			break;
2928c2ecf20Sopenharmony_ci		}
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci	stop_ptraced_child(pid, 0, 1);
2958c2ecf20Sopenharmony_ci	os_info("OK\n");
2968c2ecf20Sopenharmony_ci	check_sysemu();
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ciextern void check_tmpexec(void);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic void __init check_coredump_limit(void)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	struct rlimit lim;
3048c2ecf20Sopenharmony_ci	int err = getrlimit(RLIMIT_CORE, &lim);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	if (err) {
3078c2ecf20Sopenharmony_ci		perror("Getting core dump limit");
3088c2ecf20Sopenharmony_ci		return;
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	os_info("Core dump limits :\n\tsoft - ");
3128c2ecf20Sopenharmony_ci	if (lim.rlim_cur == RLIM_INFINITY)
3138c2ecf20Sopenharmony_ci		os_info("NONE\n");
3148c2ecf20Sopenharmony_ci	else
3158c2ecf20Sopenharmony_ci		os_info("%llu\n", (unsigned long long)lim.rlim_cur);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	os_info("\thard - ");
3188c2ecf20Sopenharmony_ci	if (lim.rlim_max == RLIM_INFINITY)
3198c2ecf20Sopenharmony_ci		os_info("NONE\n");
3208c2ecf20Sopenharmony_ci	else
3218c2ecf20Sopenharmony_ci		os_info("%llu\n", (unsigned long long)lim.rlim_max);
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_civoid __init os_early_checks(void)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	int pid;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/* Print out the core dump limits early */
3298c2ecf20Sopenharmony_ci	check_coredump_limit();
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	check_ptrace();
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	/* Need to check this early because mmapping happens before the
3348c2ecf20Sopenharmony_ci	 * kernel is running.
3358c2ecf20Sopenharmony_ci	 */
3368c2ecf20Sopenharmony_ci	check_tmpexec();
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	pid = start_ptraced_child();
3398c2ecf20Sopenharmony_ci	if (init_pid_registers(pid))
3408c2ecf20Sopenharmony_ci		fatal("Failed to initialize default registers");
3418c2ecf20Sopenharmony_ci	stop_ptraced_child(pid, 1, 1);
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ciint __init parse_iomem(char *str, int *add)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct iomem_region *new;
3478c2ecf20Sopenharmony_ci	struct stat64 buf;
3488c2ecf20Sopenharmony_ci	char *file, *driver;
3498c2ecf20Sopenharmony_ci	int fd, size;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	driver = str;
3528c2ecf20Sopenharmony_ci	file = strchr(str,',');
3538c2ecf20Sopenharmony_ci	if (file == NULL) {
3548c2ecf20Sopenharmony_ci		os_warn("parse_iomem : failed to parse iomem\n");
3558c2ecf20Sopenharmony_ci		goto out;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci	*file = '\0';
3588c2ecf20Sopenharmony_ci	file++;
3598c2ecf20Sopenharmony_ci	fd = open(file, O_RDWR, 0);
3608c2ecf20Sopenharmony_ci	if (fd < 0) {
3618c2ecf20Sopenharmony_ci		perror("parse_iomem - Couldn't open io file");
3628c2ecf20Sopenharmony_ci		goto out;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if (fstat64(fd, &buf) < 0) {
3668c2ecf20Sopenharmony_ci		perror("parse_iomem - cannot stat_fd file");
3678c2ecf20Sopenharmony_ci		goto out_close;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	new = malloc(sizeof(*new));
3718c2ecf20Sopenharmony_ci	if (new == NULL) {
3728c2ecf20Sopenharmony_ci		perror("Couldn't allocate iomem_region struct");
3738c2ecf20Sopenharmony_ci		goto out_close;
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	*new = ((struct iomem_region) { .next		= iomem_regions,
3798c2ecf20Sopenharmony_ci					.driver		= driver,
3808c2ecf20Sopenharmony_ci					.fd		= fd,
3818c2ecf20Sopenharmony_ci					.size		= size,
3828c2ecf20Sopenharmony_ci					.phys		= 0,
3838c2ecf20Sopenharmony_ci					.virt		= 0 });
3848c2ecf20Sopenharmony_ci	iomem_regions = new;
3858c2ecf20Sopenharmony_ci	iomem_size += new->size + UM_KERN_PAGE_SIZE;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	return 0;
3888c2ecf20Sopenharmony_ci out_close:
3898c2ecf20Sopenharmony_ci	close(fd);
3908c2ecf20Sopenharmony_ci out:
3918c2ecf20Sopenharmony_ci	return 1;
3928c2ecf20Sopenharmony_ci}
393