162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <stdio.h>
762306a36Sopenharmony_ci#include <stdlib.h>
862306a36Sopenharmony_ci#include <stdarg.h>
962306a36Sopenharmony_ci#include <unistd.h>
1062306a36Sopenharmony_ci#include <errno.h>
1162306a36Sopenharmony_ci#include <fcntl.h>
1262306a36Sopenharmony_ci#include <sched.h>
1362306a36Sopenharmony_ci#include <signal.h>
1462306a36Sopenharmony_ci#include <string.h>
1562306a36Sopenharmony_ci#include <sys/mman.h>
1662306a36Sopenharmony_ci#include <sys/stat.h>
1762306a36Sopenharmony_ci#include <sys/wait.h>
1862306a36Sopenharmony_ci#include <sys/time.h>
1962306a36Sopenharmony_ci#include <sys/resource.h>
2062306a36Sopenharmony_ci#include <asm/unistd.h>
2162306a36Sopenharmony_ci#include <init.h>
2262306a36Sopenharmony_ci#include <os.h>
2362306a36Sopenharmony_ci#include <mem_user.h>
2462306a36Sopenharmony_ci#include <ptrace_user.h>
2562306a36Sopenharmony_ci#include <registers.h>
2662306a36Sopenharmony_ci#include <skas.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic void ptrace_child(void)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	int ret;
3162306a36Sopenharmony_ci	/* Calling os_getpid because some libcs cached getpid incorrectly */
3262306a36Sopenharmony_ci	int pid = os_getpid(), ppid = getppid();
3362306a36Sopenharmony_ci	int sc_result;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	if (change_sig(SIGWINCH, 0) < 0 ||
3662306a36Sopenharmony_ci	    ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
3762306a36Sopenharmony_ci		perror("ptrace");
3862306a36Sopenharmony_ci		kill(pid, SIGKILL);
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci	kill(pid, SIGSTOP);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	/*
4362306a36Sopenharmony_ci	 * This syscall will be intercepted by the parent. Don't call more than
4462306a36Sopenharmony_ci	 * once, please.
4562306a36Sopenharmony_ci	 */
4662306a36Sopenharmony_ci	sc_result = os_getpid();
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	if (sc_result == pid)
4962306a36Sopenharmony_ci		/* Nothing modified by the parent, we are running normally. */
5062306a36Sopenharmony_ci		ret = 1;
5162306a36Sopenharmony_ci	else if (sc_result == ppid)
5262306a36Sopenharmony_ci		/*
5362306a36Sopenharmony_ci		 * Expected in check_ptrace and check_sysemu when they succeed
5462306a36Sopenharmony_ci		 * in modifying the stack frame
5562306a36Sopenharmony_ci		 */
5662306a36Sopenharmony_ci		ret = 0;
5762306a36Sopenharmony_ci	else
5862306a36Sopenharmony_ci		/* Serious trouble! This could be caused by a bug in host 2.6
5962306a36Sopenharmony_ci		 * SKAS3/2.6 patch before release -V6, together with a bug in
6062306a36Sopenharmony_ci		 * the UML code itself.
6162306a36Sopenharmony_ci		 */
6262306a36Sopenharmony_ci		ret = 2;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	exit(ret);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic void fatal_perror(const char *str)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	perror(str);
7062306a36Sopenharmony_ci	exit(1);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic void fatal(char *fmt, ...)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	va_list list;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	va_start(list, fmt);
7862306a36Sopenharmony_ci	vfprintf(stderr, fmt, list);
7962306a36Sopenharmony_ci	va_end(list);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	exit(1);
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic void non_fatal(char *fmt, ...)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	va_list list;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	va_start(list, fmt);
8962306a36Sopenharmony_ci	vfprintf(stderr, fmt, list);
9062306a36Sopenharmony_ci	va_end(list);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic int start_ptraced_child(void)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	int pid, n, status;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	fflush(stdout);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	pid = fork();
10062306a36Sopenharmony_ci	if (pid == 0)
10162306a36Sopenharmony_ci		ptrace_child();
10262306a36Sopenharmony_ci	else if (pid < 0)
10362306a36Sopenharmony_ci		fatal_perror("start_ptraced_child : fork failed");
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
10662306a36Sopenharmony_ci	if (n < 0)
10762306a36Sopenharmony_ci		fatal_perror("check_ptrace : waitpid failed");
10862306a36Sopenharmony_ci	if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
10962306a36Sopenharmony_ci		fatal("check_ptrace : expected SIGSTOP, got status = %d",
11062306a36Sopenharmony_ci		      status);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return pid;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/* When testing for SYSEMU support, if it is one of the broken versions, we
11662306a36Sopenharmony_ci * must just avoid using sysemu, not panic, but only if SYSEMU features are
11762306a36Sopenharmony_ci * broken.
11862306a36Sopenharmony_ci * So only for SYSEMU features we test mustpanic, while normal host features
11962306a36Sopenharmony_ci * must work anyway!
12062306a36Sopenharmony_ci */
12162306a36Sopenharmony_cistatic int stop_ptraced_child(int pid, int exitcode, int mustexit)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	int status, n, ret = 0;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) {
12662306a36Sopenharmony_ci		perror("stop_ptraced_child : ptrace failed");
12762306a36Sopenharmony_ci		return -1;
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci	CATCH_EINTR(n = waitpid(pid, &status, 0));
13062306a36Sopenharmony_ci	if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
13162306a36Sopenharmony_ci		int exit_with = WEXITSTATUS(status);
13262306a36Sopenharmony_ci		if (exit_with == 2)
13362306a36Sopenharmony_ci			non_fatal("check_ptrace : child exited with status 2. "
13462306a36Sopenharmony_ci				  "\nDisabling SYSEMU support.\n");
13562306a36Sopenharmony_ci		non_fatal("check_ptrace : child exited with exitcode %d, while "
13662306a36Sopenharmony_ci			  "expecting %d; status 0x%x\n", exit_with,
13762306a36Sopenharmony_ci			  exitcode, status);
13862306a36Sopenharmony_ci		if (mustexit)
13962306a36Sopenharmony_ci			exit(1);
14062306a36Sopenharmony_ci		ret = -1;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return ret;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/* Changed only during early boot */
14762306a36Sopenharmony_cistatic int force_sysemu_disabled = 0;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic int __init nosysemu_cmd_param(char *str, int* add)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	force_sysemu_disabled = 1;
15262306a36Sopenharmony_ci	return 0;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci__uml_setup("nosysemu", nosysemu_cmd_param,
15662306a36Sopenharmony_ci"nosysemu\n"
15762306a36Sopenharmony_ci"    Turns off syscall emulation patch for ptrace (SYSEMU).\n"
15862306a36Sopenharmony_ci"    SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
15962306a36Sopenharmony_ci"    behaviour of ptrace() and helps reduce host context switch rates.\n"
16062306a36Sopenharmony_ci"    To make it work, you need a kernel patch for your host, too.\n"
16162306a36Sopenharmony_ci"    See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n"
16262306a36Sopenharmony_ci"    information.\n\n");
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic void __init check_sysemu(void)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	unsigned long regs[MAX_REG_NR];
16762306a36Sopenharmony_ci	int pid, n, status, count=0;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	os_info("Checking syscall emulation patch for ptrace...");
17062306a36Sopenharmony_ci	sysemu_supported = 0;
17162306a36Sopenharmony_ci	pid = start_ptraced_child();
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
17462306a36Sopenharmony_ci		goto fail;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
17762306a36Sopenharmony_ci	if (n < 0)
17862306a36Sopenharmony_ci		fatal_perror("check_sysemu : wait failed");
17962306a36Sopenharmony_ci	if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
18062306a36Sopenharmony_ci		fatal("check_sysemu : expected SIGTRAP, got status = %d\n",
18162306a36Sopenharmony_ci		      status);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
18462306a36Sopenharmony_ci		fatal_perror("check_sysemu : PTRACE_GETREGS failed");
18562306a36Sopenharmony_ci	if (PT_SYSCALL_NR(regs) != __NR_getpid) {
18662306a36Sopenharmony_ci		non_fatal("check_sysemu got system call number %d, "
18762306a36Sopenharmony_ci			  "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid);
18862306a36Sopenharmony_ci		goto fail;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid());
19262306a36Sopenharmony_ci	if (n < 0) {
19362306a36Sopenharmony_ci		non_fatal("check_sysemu : failed to modify system call "
19462306a36Sopenharmony_ci			  "return");
19562306a36Sopenharmony_ci		goto fail;
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	if (stop_ptraced_child(pid, 0, 0) < 0)
19962306a36Sopenharmony_ci		goto fail_stopped;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	sysemu_supported = 1;
20262306a36Sopenharmony_ci	os_info("OK\n");
20362306a36Sopenharmony_ci	set_using_sysemu(!force_sysemu_disabled);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	os_info("Checking advanced syscall emulation patch for ptrace...");
20662306a36Sopenharmony_ci	pid = start_ptraced_child();
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
20962306a36Sopenharmony_ci		   (void *) PTRACE_O_TRACESYSGOOD) < 0))
21062306a36Sopenharmony_ci		fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed");
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	while (1) {
21362306a36Sopenharmony_ci		count++;
21462306a36Sopenharmony_ci		if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
21562306a36Sopenharmony_ci			goto fail;
21662306a36Sopenharmony_ci		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
21762306a36Sopenharmony_ci		if (n < 0)
21862306a36Sopenharmony_ci			fatal_perror("check_sysemu: wait failed");
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		if (WIFSTOPPED(status) &&
22162306a36Sopenharmony_ci		    (WSTOPSIG(status) == (SIGTRAP|0x80))) {
22262306a36Sopenharmony_ci			if (!count) {
22362306a36Sopenharmony_ci				non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
22462306a36Sopenharmony_ci					  "doesn't singlestep");
22562306a36Sopenharmony_ci				goto fail;
22662306a36Sopenharmony_ci			}
22762306a36Sopenharmony_ci			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
22862306a36Sopenharmony_ci				   os_getpid());
22962306a36Sopenharmony_ci			if (n < 0)
23062306a36Sopenharmony_ci				fatal_perror("check_sysemu : failed to modify "
23162306a36Sopenharmony_ci					     "system call return");
23262306a36Sopenharmony_ci			break;
23362306a36Sopenharmony_ci		}
23462306a36Sopenharmony_ci		else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
23562306a36Sopenharmony_ci			count++;
23662306a36Sopenharmony_ci		else {
23762306a36Sopenharmony_ci			non_fatal("check_sysemu: expected SIGTRAP or "
23862306a36Sopenharmony_ci				  "(SIGTRAP | 0x80), got status = %d\n",
23962306a36Sopenharmony_ci				  status);
24062306a36Sopenharmony_ci			goto fail;
24162306a36Sopenharmony_ci		}
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci	if (stop_ptraced_child(pid, 0, 0) < 0)
24462306a36Sopenharmony_ci		goto fail_stopped;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	sysemu_supported = 2;
24762306a36Sopenharmony_ci	os_info("OK\n");
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (!force_sysemu_disabled)
25062306a36Sopenharmony_ci		set_using_sysemu(sysemu_supported);
25162306a36Sopenharmony_ci	return;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cifail:
25462306a36Sopenharmony_ci	stop_ptraced_child(pid, 1, 0);
25562306a36Sopenharmony_cifail_stopped:
25662306a36Sopenharmony_ci	non_fatal("missing\n");
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic void __init check_ptrace(void)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	int pid, syscall, n, status;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	os_info("Checking that ptrace can change system call numbers...");
26462306a36Sopenharmony_ci	pid = start_ptraced_child();
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
26762306a36Sopenharmony_ci		   (void *) PTRACE_O_TRACESYSGOOD) < 0))
26862306a36Sopenharmony_ci		fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed");
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	while (1) {
27162306a36Sopenharmony_ci		if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
27262306a36Sopenharmony_ci			fatal_perror("check_ptrace : ptrace failed");
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
27562306a36Sopenharmony_ci		if (n < 0)
27662306a36Sopenharmony_ci			fatal_perror("check_ptrace : wait failed");
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		if (!WIFSTOPPED(status) ||
27962306a36Sopenharmony_ci		   (WSTOPSIG(status) != (SIGTRAP | 0x80)))
28062306a36Sopenharmony_ci			fatal("check_ptrace : expected (SIGTRAP|0x80), "
28162306a36Sopenharmony_ci			       "got status = %d", status);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
28462306a36Sopenharmony_ci				 0);
28562306a36Sopenharmony_ci		if (syscall == __NR_getpid) {
28662306a36Sopenharmony_ci			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
28762306a36Sopenharmony_ci				   __NR_getppid);
28862306a36Sopenharmony_ci			if (n < 0)
28962306a36Sopenharmony_ci				fatal_perror("check_ptrace : failed to modify "
29062306a36Sopenharmony_ci					     "system call");
29162306a36Sopenharmony_ci			break;
29262306a36Sopenharmony_ci		}
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci	stop_ptraced_child(pid, 0, 1);
29562306a36Sopenharmony_ci	os_info("OK\n");
29662306a36Sopenharmony_ci	check_sysemu();
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ciextern void check_tmpexec(void);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic void __init check_coredump_limit(void)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct rlimit lim;
30462306a36Sopenharmony_ci	int err = getrlimit(RLIMIT_CORE, &lim);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	if (err) {
30762306a36Sopenharmony_ci		perror("Getting core dump limit");
30862306a36Sopenharmony_ci		return;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	os_info("Core dump limits :\n\tsoft - ");
31262306a36Sopenharmony_ci	if (lim.rlim_cur == RLIM_INFINITY)
31362306a36Sopenharmony_ci		os_info("NONE\n");
31462306a36Sopenharmony_ci	else
31562306a36Sopenharmony_ci		os_info("%llu\n", (unsigned long long)lim.rlim_cur);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	os_info("\thard - ");
31862306a36Sopenharmony_ci	if (lim.rlim_max == RLIM_INFINITY)
31962306a36Sopenharmony_ci		os_info("NONE\n");
32062306a36Sopenharmony_ci	else
32162306a36Sopenharmony_ci		os_info("%llu\n", (unsigned long long)lim.rlim_max);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_civoid  __init get_host_cpu_features(
32562306a36Sopenharmony_ci		void (*flags_helper_func)(char *line),
32662306a36Sopenharmony_ci		void (*cache_helper_func)(char *line))
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	FILE *cpuinfo;
32962306a36Sopenharmony_ci	char *line = NULL;
33062306a36Sopenharmony_ci	size_t len = 0;
33162306a36Sopenharmony_ci	int done_parsing = 0;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	cpuinfo = fopen("/proc/cpuinfo", "r");
33462306a36Sopenharmony_ci	if (cpuinfo == NULL) {
33562306a36Sopenharmony_ci		os_info("Failed to get host CPU features\n");
33662306a36Sopenharmony_ci	} else {
33762306a36Sopenharmony_ci		while ((getline(&line, &len, cpuinfo)) != -1) {
33862306a36Sopenharmony_ci			if (strstr(line, "flags")) {
33962306a36Sopenharmony_ci				flags_helper_func(line);
34062306a36Sopenharmony_ci				done_parsing++;
34162306a36Sopenharmony_ci			}
34262306a36Sopenharmony_ci			if (strstr(line, "cache_alignment")) {
34362306a36Sopenharmony_ci				cache_helper_func(line);
34462306a36Sopenharmony_ci				done_parsing++;
34562306a36Sopenharmony_ci			}
34662306a36Sopenharmony_ci			free(line);
34762306a36Sopenharmony_ci			line = NULL;
34862306a36Sopenharmony_ci			if (done_parsing > 1)
34962306a36Sopenharmony_ci				break;
35062306a36Sopenharmony_ci		}
35162306a36Sopenharmony_ci		fclose(cpuinfo);
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_civoid __init os_early_checks(void)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	int pid;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	/* Print out the core dump limits early */
36162306a36Sopenharmony_ci	check_coredump_limit();
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	check_ptrace();
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* Need to check this early because mmapping happens before the
36662306a36Sopenharmony_ci	 * kernel is running.
36762306a36Sopenharmony_ci	 */
36862306a36Sopenharmony_ci	check_tmpexec();
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	pid = start_ptraced_child();
37162306a36Sopenharmony_ci	if (init_pid_registers(pid))
37262306a36Sopenharmony_ci		fatal("Failed to initialize default registers");
37362306a36Sopenharmony_ci	stop_ptraced_child(pid, 1, 1);
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ciint __init parse_iomem(char *str, int *add)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	struct iomem_region *new;
37962306a36Sopenharmony_ci	struct stat64 buf;
38062306a36Sopenharmony_ci	char *file, *driver;
38162306a36Sopenharmony_ci	int fd, size;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	driver = str;
38462306a36Sopenharmony_ci	file = strchr(str,',');
38562306a36Sopenharmony_ci	if (file == NULL) {
38662306a36Sopenharmony_ci		os_warn("parse_iomem : failed to parse iomem\n");
38762306a36Sopenharmony_ci		goto out;
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci	*file = '\0';
39062306a36Sopenharmony_ci	file++;
39162306a36Sopenharmony_ci	fd = open(file, O_RDWR, 0);
39262306a36Sopenharmony_ci	if (fd < 0) {
39362306a36Sopenharmony_ci		perror("parse_iomem - Couldn't open io file");
39462306a36Sopenharmony_ci		goto out;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (fstat64(fd, &buf) < 0) {
39862306a36Sopenharmony_ci		perror("parse_iomem - cannot stat_fd file");
39962306a36Sopenharmony_ci		goto out_close;
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	new = malloc(sizeof(*new));
40362306a36Sopenharmony_ci	if (new == NULL) {
40462306a36Sopenharmony_ci		perror("Couldn't allocate iomem_region struct");
40562306a36Sopenharmony_ci		goto out_close;
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	*new = ((struct iomem_region) { .next		= iomem_regions,
41162306a36Sopenharmony_ci					.driver		= driver,
41262306a36Sopenharmony_ci					.fd		= fd,
41362306a36Sopenharmony_ci					.size		= size,
41462306a36Sopenharmony_ci					.phys		= 0,
41562306a36Sopenharmony_ci					.virt		= 0 });
41662306a36Sopenharmony_ci	iomem_regions = new;
41762306a36Sopenharmony_ci	iomem_size += new->size + UM_KERN_PAGE_SIZE;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return 0;
42062306a36Sopenharmony_ci out_close:
42162306a36Sopenharmony_ci	close(fd);
42262306a36Sopenharmony_ci out:
42362306a36Sopenharmony_ci	return 1;
42462306a36Sopenharmony_ci}
425