162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
462306a36Sopenharmony_ci * Copyright (C) 2002- 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <stdlib.h>
862306a36Sopenharmony_ci#include <stdbool.h>
962306a36Sopenharmony_ci#include <unistd.h>
1062306a36Sopenharmony_ci#include <sched.h>
1162306a36Sopenharmony_ci#include <errno.h>
1262306a36Sopenharmony_ci#include <string.h>
1362306a36Sopenharmony_ci#include <sys/mman.h>
1462306a36Sopenharmony_ci#include <sys/wait.h>
1562306a36Sopenharmony_ci#include <asm/unistd.h>
1662306a36Sopenharmony_ci#include <as-layout.h>
1762306a36Sopenharmony_ci#include <init.h>
1862306a36Sopenharmony_ci#include <kern_util.h>
1962306a36Sopenharmony_ci#include <mem.h>
2062306a36Sopenharmony_ci#include <os.h>
2162306a36Sopenharmony_ci#include <ptrace_user.h>
2262306a36Sopenharmony_ci#include <registers.h>
2362306a36Sopenharmony_ci#include <skas.h>
2462306a36Sopenharmony_ci#include <sysdep/stub.h>
2562306a36Sopenharmony_ci#include <linux/threads.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciint is_skas_winch(int pid, int fd, void *data)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	return pid == getpgrp();
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic const char *ptrace_reg_name(int idx)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci#define R(n) case HOST_##n: return #n
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	switch (idx) {
3762306a36Sopenharmony_ci#ifdef __x86_64__
3862306a36Sopenharmony_ci	R(BX);
3962306a36Sopenharmony_ci	R(CX);
4062306a36Sopenharmony_ci	R(DI);
4162306a36Sopenharmony_ci	R(SI);
4262306a36Sopenharmony_ci	R(DX);
4362306a36Sopenharmony_ci	R(BP);
4462306a36Sopenharmony_ci	R(AX);
4562306a36Sopenharmony_ci	R(R8);
4662306a36Sopenharmony_ci	R(R9);
4762306a36Sopenharmony_ci	R(R10);
4862306a36Sopenharmony_ci	R(R11);
4962306a36Sopenharmony_ci	R(R12);
5062306a36Sopenharmony_ci	R(R13);
5162306a36Sopenharmony_ci	R(R14);
5262306a36Sopenharmony_ci	R(R15);
5362306a36Sopenharmony_ci	R(ORIG_AX);
5462306a36Sopenharmony_ci	R(CS);
5562306a36Sopenharmony_ci	R(SS);
5662306a36Sopenharmony_ci	R(EFLAGS);
5762306a36Sopenharmony_ci#elif defined(__i386__)
5862306a36Sopenharmony_ci	R(IP);
5962306a36Sopenharmony_ci	R(SP);
6062306a36Sopenharmony_ci	R(EFLAGS);
6162306a36Sopenharmony_ci	R(AX);
6262306a36Sopenharmony_ci	R(BX);
6362306a36Sopenharmony_ci	R(CX);
6462306a36Sopenharmony_ci	R(DX);
6562306a36Sopenharmony_ci	R(SI);
6662306a36Sopenharmony_ci	R(DI);
6762306a36Sopenharmony_ci	R(BP);
6862306a36Sopenharmony_ci	R(CS);
6962306a36Sopenharmony_ci	R(SS);
7062306a36Sopenharmony_ci	R(DS);
7162306a36Sopenharmony_ci	R(FS);
7262306a36Sopenharmony_ci	R(ES);
7362306a36Sopenharmony_ci	R(GS);
7462306a36Sopenharmony_ci	R(ORIG_AX);
7562306a36Sopenharmony_ci#endif
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci	return "";
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic int ptrace_dump_regs(int pid)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	unsigned long regs[MAX_REG_NR];
8362306a36Sopenharmony_ci	int i;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
8662306a36Sopenharmony_ci		return -errno;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	printk(UM_KERN_ERR "Stub registers -\n");
8962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(regs); i++) {
9062306a36Sopenharmony_ci		const char *regname = ptrace_reg_name(i);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci		printk(UM_KERN_ERR "\t%s\t(%2d): %lx\n", regname, i, regs[i]);
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	return 0;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/*
9962306a36Sopenharmony_ci * Signals that are OK to receive in the stub - we'll just continue it.
10062306a36Sopenharmony_ci * SIGWINCH will happen when UML is inside a detached screen.
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_ci#define STUB_SIG_MASK ((1 << SIGALRM) | (1 << SIGWINCH))
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/* Signals that the stub will finish with - anything else is an error */
10562306a36Sopenharmony_ci#define STUB_DONE_MASK (1 << SIGTRAP)
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_civoid wait_stub_done(int pid)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	int n, status, err;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	while (1) {
11262306a36Sopenharmony_ci		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL));
11362306a36Sopenharmony_ci		if ((n < 0) || !WIFSTOPPED(status))
11462306a36Sopenharmony_ci			goto bad_wait;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci		if (((1 << WSTOPSIG(status)) & STUB_SIG_MASK) == 0)
11762306a36Sopenharmony_ci			break;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci		err = ptrace(PTRACE_CONT, pid, 0, 0);
12062306a36Sopenharmony_ci		if (err) {
12162306a36Sopenharmony_ci			printk(UM_KERN_ERR "%s : continue failed, errno = %d\n",
12262306a36Sopenharmony_ci			       __func__, errno);
12362306a36Sopenharmony_ci			fatal_sigsegv();
12462306a36Sopenharmony_ci		}
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0)
12862306a36Sopenharmony_ci		return;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cibad_wait:
13162306a36Sopenharmony_ci	err = ptrace_dump_regs(pid);
13262306a36Sopenharmony_ci	if (err)
13362306a36Sopenharmony_ci		printk(UM_KERN_ERR "Failed to get registers from stub, errno = %d\n",
13462306a36Sopenharmony_ci		       -err);
13562306a36Sopenharmony_ci	printk(UM_KERN_ERR "%s : failed to wait for SIGTRAP, pid = %d, n = %d, errno = %d, status = 0x%x\n",
13662306a36Sopenharmony_ci	       __func__, pid, n, errno, status);
13762306a36Sopenharmony_ci	fatal_sigsegv();
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ciextern unsigned long current_stub_stack(void);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic void get_skas_faultinfo(int pid, struct faultinfo *fi, unsigned long *aux_fp_regs)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	int err;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	err = get_fp_registers(pid, aux_fp_regs);
14762306a36Sopenharmony_ci	if (err < 0) {
14862306a36Sopenharmony_ci		printk(UM_KERN_ERR "save_fp_registers returned %d\n",
14962306a36Sopenharmony_ci		       err);
15062306a36Sopenharmony_ci		fatal_sigsegv();
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci	err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV);
15362306a36Sopenharmony_ci	if (err) {
15462306a36Sopenharmony_ci		printk(UM_KERN_ERR "Failed to continue stub, pid = %d, "
15562306a36Sopenharmony_ci		       "errno = %d\n", pid, errno);
15662306a36Sopenharmony_ci		fatal_sigsegv();
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci	wait_stub_done(pid);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/*
16162306a36Sopenharmony_ci	 * faultinfo is prepared by the stub_segv_handler at start of
16262306a36Sopenharmony_ci	 * the stub stack page. We just have to copy it.
16362306a36Sopenharmony_ci	 */
16462306a36Sopenharmony_ci	memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	err = put_fp_registers(pid, aux_fp_regs);
16762306a36Sopenharmony_ci	if (err < 0) {
16862306a36Sopenharmony_ci		printk(UM_KERN_ERR "put_fp_registers returned %d\n",
16962306a36Sopenharmony_ci		       err);
17062306a36Sopenharmony_ci		fatal_sigsegv();
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic void handle_segv(int pid, struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	get_skas_faultinfo(pid, &regs->faultinfo, aux_fp_regs);
17762306a36Sopenharmony_ci	segv(regs->faultinfo, 0, 1, NULL);
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/*
18162306a36Sopenharmony_ci * To use the same value of using_sysemu as the caller, ask it that value
18262306a36Sopenharmony_ci * (in local_using_sysemu
18362306a36Sopenharmony_ci */
18462306a36Sopenharmony_cistatic void handle_trap(int pid, struct uml_pt_regs *regs,
18562306a36Sopenharmony_ci			int local_using_sysemu)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	int err, status;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END))
19062306a36Sopenharmony_ci		fatal_sigsegv();
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (!local_using_sysemu)
19362306a36Sopenharmony_ci	{
19462306a36Sopenharmony_ci		err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
19562306a36Sopenharmony_ci			     __NR_getpid);
19662306a36Sopenharmony_ci		if (err < 0) {
19762306a36Sopenharmony_ci			printk(UM_KERN_ERR "%s - nullifying syscall failed, errno = %d\n",
19862306a36Sopenharmony_ci			       __func__, errno);
19962306a36Sopenharmony_ci			fatal_sigsegv();
20062306a36Sopenharmony_ci		}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci		err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
20362306a36Sopenharmony_ci		if (err < 0) {
20462306a36Sopenharmony_ci			printk(UM_KERN_ERR "%s - continuing to end of syscall failed, errno = %d\n",
20562306a36Sopenharmony_ci			       __func__, errno);
20662306a36Sopenharmony_ci			fatal_sigsegv();
20762306a36Sopenharmony_ci		}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL));
21062306a36Sopenharmony_ci		if ((err < 0) || !WIFSTOPPED(status) ||
21162306a36Sopenharmony_ci		    (WSTOPSIG(status) != SIGTRAP + 0x80)) {
21262306a36Sopenharmony_ci			err = ptrace_dump_regs(pid);
21362306a36Sopenharmony_ci			if (err)
21462306a36Sopenharmony_ci				printk(UM_KERN_ERR "Failed to get registers from process, errno = %d\n",
21562306a36Sopenharmony_ci				       -err);
21662306a36Sopenharmony_ci			printk(UM_KERN_ERR "%s - failed to wait at end of syscall, errno = %d, status = %d\n",
21762306a36Sopenharmony_ci			       __func__, errno, status);
21862306a36Sopenharmony_ci			fatal_sigsegv();
21962306a36Sopenharmony_ci		}
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	handle_syscall(regs);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ciextern char __syscall_stub_start[];
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci/**
22862306a36Sopenharmony_ci * userspace_tramp() - userspace trampoline
22962306a36Sopenharmony_ci * @stack:	pointer to the new userspace stack page, can be NULL, if? FIXME:
23062306a36Sopenharmony_ci *
23162306a36Sopenharmony_ci * The userspace trampoline is used to setup a new userspace process in start_userspace() after it was clone()'ed.
23262306a36Sopenharmony_ci * This function will run on a temporary stack page.
23362306a36Sopenharmony_ci * It ptrace()'es itself, then
23462306a36Sopenharmony_ci * Two pages are mapped into the userspace address space:
23562306a36Sopenharmony_ci * - STUB_CODE (with EXEC), which contains the skas stub code
23662306a36Sopenharmony_ci * - STUB_DATA (with R/W), which contains a data page that is used to transfer certain data between the UML userspace process and the UML kernel.
23762306a36Sopenharmony_ci * Also for the userspace process a SIGSEGV handler is installed to catch pagefaults in the userspace process.
23862306a36Sopenharmony_ci * And last the process stops itself to give control to the UML kernel for this userspace process.
23962306a36Sopenharmony_ci *
24062306a36Sopenharmony_ci * Return: Always zero, otherwise the current userspace process is ended with non null exit() call
24162306a36Sopenharmony_ci */
24262306a36Sopenharmony_cistatic int userspace_tramp(void *stack)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	void *addr;
24562306a36Sopenharmony_ci	int fd;
24662306a36Sopenharmony_ci	unsigned long long offset;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	ptrace(PTRACE_TRACEME, 0, 0, 0);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	signal(SIGTERM, SIG_DFL);
25162306a36Sopenharmony_ci	signal(SIGWINCH, SIG_IGN);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	fd = phys_mapping(uml_to_phys(__syscall_stub_start), &offset);
25462306a36Sopenharmony_ci	addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE,
25562306a36Sopenharmony_ci		      PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
25662306a36Sopenharmony_ci	if (addr == MAP_FAILED) {
25762306a36Sopenharmony_ci		printk(UM_KERN_ERR "mapping mmap stub at 0x%lx failed, errno = %d\n",
25862306a36Sopenharmony_ci		       STUB_CODE, errno);
25962306a36Sopenharmony_ci		exit(1);
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	if (stack != NULL) {
26362306a36Sopenharmony_ci		fd = phys_mapping(uml_to_phys(stack), &offset);
26462306a36Sopenharmony_ci		addr = mmap((void *) STUB_DATA,
26562306a36Sopenharmony_ci			    STUB_DATA_PAGES * UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
26662306a36Sopenharmony_ci			    MAP_FIXED | MAP_SHARED, fd, offset);
26762306a36Sopenharmony_ci		if (addr == MAP_FAILED) {
26862306a36Sopenharmony_ci			printk(UM_KERN_ERR "mapping segfault stack at 0x%lx failed, errno = %d\n",
26962306a36Sopenharmony_ci			       STUB_DATA, errno);
27062306a36Sopenharmony_ci			exit(1);
27162306a36Sopenharmony_ci		}
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci	if (stack != NULL) {
27462306a36Sopenharmony_ci		struct sigaction sa;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci		unsigned long v = STUB_CODE +
27762306a36Sopenharmony_ci				  (unsigned long) stub_segv_handler -
27862306a36Sopenharmony_ci				  (unsigned long) __syscall_stub_start;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci		set_sigstack((void *) STUB_DATA, STUB_DATA_PAGES * UM_KERN_PAGE_SIZE);
28162306a36Sopenharmony_ci		sigemptyset(&sa.sa_mask);
28262306a36Sopenharmony_ci		sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO;
28362306a36Sopenharmony_ci		sa.sa_sigaction = (void *) v;
28462306a36Sopenharmony_ci		sa.sa_restorer = NULL;
28562306a36Sopenharmony_ci		if (sigaction(SIGSEGV, &sa, NULL) < 0) {
28662306a36Sopenharmony_ci			printk(UM_KERN_ERR "%s - setting SIGSEGV handler failed - errno = %d\n",
28762306a36Sopenharmony_ci			       __func__, errno);
28862306a36Sopenharmony_ci			exit(1);
28962306a36Sopenharmony_ci		}
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	kill(os_getpid(), SIGSTOP);
29362306a36Sopenharmony_ci	return 0;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ciint userspace_pid[NR_CPUS];
29762306a36Sopenharmony_ciint kill_userspace_mm[NR_CPUS];
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci/**
30062306a36Sopenharmony_ci * start_userspace() - prepare a new userspace process
30162306a36Sopenharmony_ci * @stub_stack:	pointer to the stub stack. Can be NULL, if? FIXME:
30262306a36Sopenharmony_ci *
30362306a36Sopenharmony_ci * Setups a new temporary stack page that is used while userspace_tramp() runs
30462306a36Sopenharmony_ci * Clones the kernel process into a new userspace process, with FDs only.
30562306a36Sopenharmony_ci *
30662306a36Sopenharmony_ci * Return: When positive: the process id of the new userspace process,
30762306a36Sopenharmony_ci *         when negative: an error number.
30862306a36Sopenharmony_ci * FIXME: can PIDs become negative?!
30962306a36Sopenharmony_ci */
31062306a36Sopenharmony_ciint start_userspace(unsigned long stub_stack)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	void *stack;
31362306a36Sopenharmony_ci	unsigned long sp;
31462306a36Sopenharmony_ci	int pid, status, n, flags, err;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/* setup a temporary stack page */
31762306a36Sopenharmony_ci	stack = mmap(NULL, UM_KERN_PAGE_SIZE,
31862306a36Sopenharmony_ci		     PROT_READ | PROT_WRITE | PROT_EXEC,
31962306a36Sopenharmony_ci		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
32062306a36Sopenharmony_ci	if (stack == MAP_FAILED) {
32162306a36Sopenharmony_ci		err = -errno;
32262306a36Sopenharmony_ci		printk(UM_KERN_ERR "%s : mmap failed, errno = %d\n",
32362306a36Sopenharmony_ci		       __func__, errno);
32462306a36Sopenharmony_ci		return err;
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/* set stack pointer to the end of the stack page, so it can grow downwards */
32862306a36Sopenharmony_ci	sp = (unsigned long)stack + UM_KERN_PAGE_SIZE;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	flags = CLONE_FILES | SIGCHLD;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	/* clone into new userspace process */
33362306a36Sopenharmony_ci	pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
33462306a36Sopenharmony_ci	if (pid < 0) {
33562306a36Sopenharmony_ci		err = -errno;
33662306a36Sopenharmony_ci		printk(UM_KERN_ERR "%s : clone failed, errno = %d\n",
33762306a36Sopenharmony_ci		       __func__, errno);
33862306a36Sopenharmony_ci		return err;
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	do {
34262306a36Sopenharmony_ci		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL));
34362306a36Sopenharmony_ci		if (n < 0) {
34462306a36Sopenharmony_ci			err = -errno;
34562306a36Sopenharmony_ci			printk(UM_KERN_ERR "%s : wait failed, errno = %d\n",
34662306a36Sopenharmony_ci			       __func__, errno);
34762306a36Sopenharmony_ci			goto out_kill;
34862306a36Sopenharmony_ci		}
34962306a36Sopenharmony_ci	} while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGALRM));
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) {
35262306a36Sopenharmony_ci		err = -EINVAL;
35362306a36Sopenharmony_ci		printk(UM_KERN_ERR "%s : expected SIGSTOP, got status = %d\n",
35462306a36Sopenharmony_ci		       __func__, status);
35562306a36Sopenharmony_ci		goto out_kill;
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
35962306a36Sopenharmony_ci		   (void *) PTRACE_O_TRACESYSGOOD) < 0) {
36062306a36Sopenharmony_ci		err = -errno;
36162306a36Sopenharmony_ci		printk(UM_KERN_ERR "%s : PTRACE_OLDSETOPTIONS failed, errno = %d\n",
36262306a36Sopenharmony_ci		       __func__, errno);
36362306a36Sopenharmony_ci		goto out_kill;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (munmap(stack, UM_KERN_PAGE_SIZE) < 0) {
36762306a36Sopenharmony_ci		err = -errno;
36862306a36Sopenharmony_ci		printk(UM_KERN_ERR "%s : munmap failed, errno = %d\n",
36962306a36Sopenharmony_ci		       __func__, errno);
37062306a36Sopenharmony_ci		goto out_kill;
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	return pid;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci out_kill:
37662306a36Sopenharmony_ci	os_kill_ptraced_process(pid, 1);
37762306a36Sopenharmony_ci	return err;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_civoid userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	int err, status, op, pid = userspace_pid[0];
38362306a36Sopenharmony_ci	/* To prevent races if using_sysemu changes under us.*/
38462306a36Sopenharmony_ci	int local_using_sysemu;
38562306a36Sopenharmony_ci	siginfo_t si;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	/* Handle any immediate reschedules or signals */
38862306a36Sopenharmony_ci	interrupt_end();
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	while (1) {
39162306a36Sopenharmony_ci		if (kill_userspace_mm[0])
39262306a36Sopenharmony_ci			fatal_sigsegv();
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		/*
39562306a36Sopenharmony_ci		 * This can legitimately fail if the process loads a
39662306a36Sopenharmony_ci		 * bogus value into a segment register.  It will
39762306a36Sopenharmony_ci		 * segfault and PTRACE_GETREGS will read that value
39862306a36Sopenharmony_ci		 * out of the process.  However, PTRACE_SETREGS will
39962306a36Sopenharmony_ci		 * fail.  In this case, there is nothing to do but
40062306a36Sopenharmony_ci		 * just kill the process.
40162306a36Sopenharmony_ci		 */
40262306a36Sopenharmony_ci		if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) {
40362306a36Sopenharmony_ci			printk(UM_KERN_ERR "%s - ptrace set regs failed, errno = %d\n",
40462306a36Sopenharmony_ci			       __func__, errno);
40562306a36Sopenharmony_ci			fatal_sigsegv();
40662306a36Sopenharmony_ci		}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci		if (put_fp_registers(pid, regs->fp)) {
40962306a36Sopenharmony_ci			printk(UM_KERN_ERR "%s - ptrace set fp regs failed, errno = %d\n",
41062306a36Sopenharmony_ci			       __func__, errno);
41162306a36Sopenharmony_ci			fatal_sigsegv();
41262306a36Sopenharmony_ci		}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci		/* Now we set local_using_sysemu to be used for one loop */
41562306a36Sopenharmony_ci		local_using_sysemu = get_using_sysemu();
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci		op = SELECT_PTRACE_OPERATION(local_using_sysemu,
41862306a36Sopenharmony_ci					     singlestepping(NULL));
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci		if (ptrace(op, pid, 0, 0)) {
42162306a36Sopenharmony_ci			printk(UM_KERN_ERR "%s - ptrace continue failed, op = %d, errno = %d\n",
42262306a36Sopenharmony_ci			       __func__, op, errno);
42362306a36Sopenharmony_ci			fatal_sigsegv();
42462306a36Sopenharmony_ci		}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL));
42762306a36Sopenharmony_ci		if (err < 0) {
42862306a36Sopenharmony_ci			printk(UM_KERN_ERR "%s - wait failed, errno = %d\n",
42962306a36Sopenharmony_ci			       __func__, errno);
43062306a36Sopenharmony_ci			fatal_sigsegv();
43162306a36Sopenharmony_ci		}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci		regs->is_user = 1;
43462306a36Sopenharmony_ci		if (ptrace(PTRACE_GETREGS, pid, 0, regs->gp)) {
43562306a36Sopenharmony_ci			printk(UM_KERN_ERR "%s - PTRACE_GETREGS failed, errno = %d\n",
43662306a36Sopenharmony_ci			       __func__, errno);
43762306a36Sopenharmony_ci			fatal_sigsegv();
43862306a36Sopenharmony_ci		}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci		if (get_fp_registers(pid, regs->fp)) {
44162306a36Sopenharmony_ci			printk(UM_KERN_ERR "%s -  get_fp_registers failed, errno = %d\n",
44262306a36Sopenharmony_ci			       __func__, errno);
44362306a36Sopenharmony_ci			fatal_sigsegv();
44462306a36Sopenharmony_ci		}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci		if (WIFSTOPPED(status)) {
44962306a36Sopenharmony_ci			int sig = WSTOPSIG(status);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci			/* These signal handlers need the si argument.
45262306a36Sopenharmony_ci			 * The SIGIO and SIGALARM handlers which constitute the
45362306a36Sopenharmony_ci			 * majority of invocations, do not use it.
45462306a36Sopenharmony_ci			 */
45562306a36Sopenharmony_ci			switch (sig) {
45662306a36Sopenharmony_ci			case SIGSEGV:
45762306a36Sopenharmony_ci			case SIGTRAP:
45862306a36Sopenharmony_ci			case SIGILL:
45962306a36Sopenharmony_ci			case SIGBUS:
46062306a36Sopenharmony_ci			case SIGFPE:
46162306a36Sopenharmony_ci			case SIGWINCH:
46262306a36Sopenharmony_ci				ptrace(PTRACE_GETSIGINFO, pid, 0, (struct siginfo *)&si);
46362306a36Sopenharmony_ci				break;
46462306a36Sopenharmony_ci			}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci			switch (sig) {
46762306a36Sopenharmony_ci			case SIGSEGV:
46862306a36Sopenharmony_ci				if (PTRACE_FULL_FAULTINFO) {
46962306a36Sopenharmony_ci					get_skas_faultinfo(pid,
47062306a36Sopenharmony_ci							   &regs->faultinfo, aux_fp_regs);
47162306a36Sopenharmony_ci					(*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si,
47262306a36Sopenharmony_ci							     regs);
47362306a36Sopenharmony_ci				}
47462306a36Sopenharmony_ci				else handle_segv(pid, regs, aux_fp_regs);
47562306a36Sopenharmony_ci				break;
47662306a36Sopenharmony_ci			case SIGTRAP + 0x80:
47762306a36Sopenharmony_ci			        handle_trap(pid, regs, local_using_sysemu);
47862306a36Sopenharmony_ci				break;
47962306a36Sopenharmony_ci			case SIGTRAP:
48062306a36Sopenharmony_ci				relay_signal(SIGTRAP, (struct siginfo *)&si, regs);
48162306a36Sopenharmony_ci				break;
48262306a36Sopenharmony_ci			case SIGALRM:
48362306a36Sopenharmony_ci				break;
48462306a36Sopenharmony_ci			case SIGIO:
48562306a36Sopenharmony_ci			case SIGILL:
48662306a36Sopenharmony_ci			case SIGBUS:
48762306a36Sopenharmony_ci			case SIGFPE:
48862306a36Sopenharmony_ci			case SIGWINCH:
48962306a36Sopenharmony_ci				block_signals_trace();
49062306a36Sopenharmony_ci				(*sig_info[sig])(sig, (struct siginfo *)&si, regs);
49162306a36Sopenharmony_ci				unblock_signals_trace();
49262306a36Sopenharmony_ci				break;
49362306a36Sopenharmony_ci			default:
49462306a36Sopenharmony_ci				printk(UM_KERN_ERR "%s - child stopped with signal %d\n",
49562306a36Sopenharmony_ci				       __func__, sig);
49662306a36Sopenharmony_ci				fatal_sigsegv();
49762306a36Sopenharmony_ci			}
49862306a36Sopenharmony_ci			pid = userspace_pid[0];
49962306a36Sopenharmony_ci			interrupt_end();
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci			/* Avoid -ERESTARTSYS handling in host */
50262306a36Sopenharmony_ci			if (PT_SYSCALL_NR_OFFSET != PT_SYSCALL_RET_OFFSET)
50362306a36Sopenharmony_ci				PT_SYSCALL_NR(regs->gp) = -1;
50462306a36Sopenharmony_ci		}
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic unsigned long thread_regs[MAX_REG_NR];
50962306a36Sopenharmony_cistatic unsigned long thread_fp_regs[FP_SIZE];
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic int __init init_thread_regs(void)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	get_safe_registers(thread_regs, thread_fp_regs);
51462306a36Sopenharmony_ci	/* Set parent's instruction pointer to start of clone-stub */
51562306a36Sopenharmony_ci	thread_regs[REGS_IP_INDEX] = STUB_CODE +
51662306a36Sopenharmony_ci				(unsigned long) stub_clone_handler -
51762306a36Sopenharmony_ci				(unsigned long) __syscall_stub_start;
51862306a36Sopenharmony_ci	thread_regs[REGS_SP_INDEX] = STUB_DATA + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE -
51962306a36Sopenharmony_ci		sizeof(void *);
52062306a36Sopenharmony_ci#ifdef __SIGNAL_FRAMESIZE
52162306a36Sopenharmony_ci	thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE;
52262306a36Sopenharmony_ci#endif
52362306a36Sopenharmony_ci	return 0;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci__initcall(init_thread_regs);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ciint copy_context_skas0(unsigned long new_stack, int pid)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	int err;
53162306a36Sopenharmony_ci	unsigned long current_stack = current_stub_stack();
53262306a36Sopenharmony_ci	struct stub_data *data = (struct stub_data *) current_stack;
53362306a36Sopenharmony_ci	struct stub_data *child_data = (struct stub_data *) new_stack;
53462306a36Sopenharmony_ci	unsigned long long new_offset;
53562306a36Sopenharmony_ci	int new_fd = phys_mapping(uml_to_phys((void *)new_stack), &new_offset);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/*
53862306a36Sopenharmony_ci	 * prepare offset and fd of child's stack as argument for parent's
53962306a36Sopenharmony_ci	 * and child's mmap2 calls
54062306a36Sopenharmony_ci	 */
54162306a36Sopenharmony_ci	*data = ((struct stub_data) {
54262306a36Sopenharmony_ci		.offset	= MMAP_OFFSET(new_offset),
54362306a36Sopenharmony_ci		.fd     = new_fd,
54462306a36Sopenharmony_ci		.parent_err = -ESRCH,
54562306a36Sopenharmony_ci		.child_err = 0,
54662306a36Sopenharmony_ci	});
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	*child_data = ((struct stub_data) {
54962306a36Sopenharmony_ci		.child_err = -ESRCH,
55062306a36Sopenharmony_ci	});
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	err = ptrace_setregs(pid, thread_regs);
55362306a36Sopenharmony_ci	if (err < 0) {
55462306a36Sopenharmony_ci		err = -errno;
55562306a36Sopenharmony_ci		printk(UM_KERN_ERR "%s : PTRACE_SETREGS failed, pid = %d, errno = %d\n",
55662306a36Sopenharmony_ci		      __func__, pid, -err);
55762306a36Sopenharmony_ci		return err;
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	err = put_fp_registers(pid, thread_fp_regs);
56162306a36Sopenharmony_ci	if (err < 0) {
56262306a36Sopenharmony_ci		printk(UM_KERN_ERR "%s : put_fp_registers failed, pid = %d, err = %d\n",
56362306a36Sopenharmony_ci		       __func__, pid, err);
56462306a36Sopenharmony_ci		return err;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	/*
56862306a36Sopenharmony_ci	 * Wait, until parent has finished its work: read child's pid from
56962306a36Sopenharmony_ci	 * parent's stack, and check, if bad result.
57062306a36Sopenharmony_ci	 */
57162306a36Sopenharmony_ci	err = ptrace(PTRACE_CONT, pid, 0, 0);
57262306a36Sopenharmony_ci	if (err) {
57362306a36Sopenharmony_ci		err = -errno;
57462306a36Sopenharmony_ci		printk(UM_KERN_ERR "Failed to continue new process, pid = %d, errno = %d\n",
57562306a36Sopenharmony_ci		       pid, errno);
57662306a36Sopenharmony_ci		return err;
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	wait_stub_done(pid);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	pid = data->parent_err;
58262306a36Sopenharmony_ci	if (pid < 0) {
58362306a36Sopenharmony_ci		printk(UM_KERN_ERR "%s - stub-parent reports error %d\n",
58462306a36Sopenharmony_ci		      __func__, -pid);
58562306a36Sopenharmony_ci		return pid;
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/*
58962306a36Sopenharmony_ci	 * Wait, until child has finished too: read child's result from
59062306a36Sopenharmony_ci	 * child's stack and check it.
59162306a36Sopenharmony_ci	 */
59262306a36Sopenharmony_ci	wait_stub_done(pid);
59362306a36Sopenharmony_ci	if (child_data->child_err != STUB_DATA) {
59462306a36Sopenharmony_ci		printk(UM_KERN_ERR "%s - stub-child %d reports error %ld\n",
59562306a36Sopenharmony_ci		       __func__, pid, data->child_err);
59662306a36Sopenharmony_ci		err = data->child_err;
59762306a36Sopenharmony_ci		goto out_kill;
59862306a36Sopenharmony_ci	}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
60162306a36Sopenharmony_ci		   (void *)PTRACE_O_TRACESYSGOOD) < 0) {
60262306a36Sopenharmony_ci		err = -errno;
60362306a36Sopenharmony_ci		printk(UM_KERN_ERR "%s : PTRACE_OLDSETOPTIONS failed, errno = %d\n",
60462306a36Sopenharmony_ci		       __func__, errno);
60562306a36Sopenharmony_ci		goto out_kill;
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	return pid;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci out_kill:
61162306a36Sopenharmony_ci	os_kill_ptraced_process(pid, 1);
61262306a36Sopenharmony_ci	return err;
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_civoid new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	(*buf)[0].JB_IP = (unsigned long) handler;
61862306a36Sopenharmony_ci	(*buf)[0].JB_SP = (unsigned long) stack + UM_THREAD_SIZE -
61962306a36Sopenharmony_ci		sizeof(void *);
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci#define INIT_JMP_NEW_THREAD 0
62362306a36Sopenharmony_ci#define INIT_JMP_CALLBACK 1
62462306a36Sopenharmony_ci#define INIT_JMP_HALT 2
62562306a36Sopenharmony_ci#define INIT_JMP_REBOOT 3
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_civoid switch_threads(jmp_buf *me, jmp_buf *you)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	if (UML_SETJMP(me) == 0)
63062306a36Sopenharmony_ci		UML_LONGJMP(you, 1);
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic jmp_buf initial_jmpbuf;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci/* XXX Make these percpu */
63662306a36Sopenharmony_cistatic void (*cb_proc)(void *arg);
63762306a36Sopenharmony_cistatic void *cb_arg;
63862306a36Sopenharmony_cistatic jmp_buf *cb_back;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ciint start_idle_thread(void *stack, jmp_buf *switch_buf)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	int n;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	set_handler(SIGWINCH);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/*
64762306a36Sopenharmony_ci	 * Can't use UML_SETJMP or UML_LONGJMP here because they save
64862306a36Sopenharmony_ci	 * and restore signals, with the possible side-effect of
64962306a36Sopenharmony_ci	 * trying to handle any signals which came when they were
65062306a36Sopenharmony_ci	 * blocked, which can't be done on this stack.
65162306a36Sopenharmony_ci	 * Signals must be blocked when jumping back here and restored
65262306a36Sopenharmony_ci	 * after returning to the jumper.
65362306a36Sopenharmony_ci	 */
65462306a36Sopenharmony_ci	n = setjmp(initial_jmpbuf);
65562306a36Sopenharmony_ci	switch (n) {
65662306a36Sopenharmony_ci	case INIT_JMP_NEW_THREAD:
65762306a36Sopenharmony_ci		(*switch_buf)[0].JB_IP = (unsigned long) uml_finishsetup;
65862306a36Sopenharmony_ci		(*switch_buf)[0].JB_SP = (unsigned long) stack +
65962306a36Sopenharmony_ci			UM_THREAD_SIZE - sizeof(void *);
66062306a36Sopenharmony_ci		break;
66162306a36Sopenharmony_ci	case INIT_JMP_CALLBACK:
66262306a36Sopenharmony_ci		(*cb_proc)(cb_arg);
66362306a36Sopenharmony_ci		longjmp(*cb_back, 1);
66462306a36Sopenharmony_ci		break;
66562306a36Sopenharmony_ci	case INIT_JMP_HALT:
66662306a36Sopenharmony_ci		kmalloc_ok = 0;
66762306a36Sopenharmony_ci		return 0;
66862306a36Sopenharmony_ci	case INIT_JMP_REBOOT:
66962306a36Sopenharmony_ci		kmalloc_ok = 0;
67062306a36Sopenharmony_ci		return 1;
67162306a36Sopenharmony_ci	default:
67262306a36Sopenharmony_ci		printk(UM_KERN_ERR "Bad sigsetjmp return in %s - %d\n",
67362306a36Sopenharmony_ci		       __func__, n);
67462306a36Sopenharmony_ci		fatal_sigsegv();
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci	longjmp(*switch_buf, 1);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	/* unreachable */
67962306a36Sopenharmony_ci	printk(UM_KERN_ERR "impossible long jump!");
68062306a36Sopenharmony_ci	fatal_sigsegv();
68162306a36Sopenharmony_ci	return 0;
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_civoid initial_thread_cb_skas(void (*proc)(void *), void *arg)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	jmp_buf here;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	cb_proc = proc;
68962306a36Sopenharmony_ci	cb_arg = arg;
69062306a36Sopenharmony_ci	cb_back = &here;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	block_signals_trace();
69362306a36Sopenharmony_ci	if (UML_SETJMP(&here) == 0)
69462306a36Sopenharmony_ci		UML_LONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK);
69562306a36Sopenharmony_ci	unblock_signals_trace();
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	cb_proc = NULL;
69862306a36Sopenharmony_ci	cb_arg = NULL;
69962306a36Sopenharmony_ci	cb_back = NULL;
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_civoid halt_skas(void)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	block_signals_trace();
70562306a36Sopenharmony_ci	UML_LONGJMP(&initial_jmpbuf, INIT_JMP_HALT);
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic bool noreboot;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_cistatic int __init noreboot_cmd_param(char *str, int *add)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	noreboot = true;
71362306a36Sopenharmony_ci	return 0;
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci__uml_setup("noreboot", noreboot_cmd_param,
71762306a36Sopenharmony_ci"noreboot\n"
71862306a36Sopenharmony_ci"    Rather than rebooting, exit always, akin to QEMU's -no-reboot option.\n"
71962306a36Sopenharmony_ci"    This is useful if you're using CONFIG_PANIC_TIMEOUT in order to catch\n"
72062306a36Sopenharmony_ci"    crashes in CI\n");
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_civoid reboot_skas(void)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci	block_signals_trace();
72562306a36Sopenharmony_ci	UML_LONGJMP(&initial_jmpbuf, noreboot ? INIT_JMP_HALT : INIT_JMP_REBOOT);
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_civoid __switch_mm(struct mm_id *mm_idp)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	userspace_pid[0] = mm_idp->u.pid;
73162306a36Sopenharmony_ci	kill_userspace_mm[0] = mm_idp->kill;
73262306a36Sopenharmony_ci}
733