blob: cd4a6ff676a8891475c9e00e1acd44043a51cbe0 [file] [log] [blame]
Gennady Sharapovabaf6972006-01-18 17:42:46 -08001/*
Anton Ivanov2eb5f312015-11-02 16:16:37 +00002 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
Jeff Dikeba180fd2007-10-16 01:27:00 -07003 * Copyright (C) 2002- 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
Gennady Sharapovabaf6972006-01-18 17:42:46 -08004 * Licensed under the GPL
5 */
6
7#include <stdlib.h>
Gennady Sharapovabaf6972006-01-18 17:42:46 -08008#include <unistd.h>
Gennady Sharapovabaf6972006-01-18 17:42:46 -08009#include <sched.h>
Jeff Dikeba180fd2007-10-16 01:27:00 -070010#include <errno.h>
11#include <string.h>
Gennady Sharapovabaf6972006-01-18 17:42:46 -080012#include <sys/mman.h>
Jeff Dikeba180fd2007-10-16 01:27:00 -070013#include <sys/wait.h>
14#include <asm/unistd.h>
Al Viro37185b32012-10-08 03:27:32 +010015#include <as-layout.h>
16#include <init.h>
17#include <kern_util.h>
18#include <mem.h>
19#include <os.h>
Al Viro37185b32012-10-08 03:27:32 +010020#include <ptrace_user.h>
21#include <registers.h>
22#include <skas.h>
Al Viro37185b32012-10-08 03:27:32 +010023#include <sysdep/stub.h>
Gennady Sharapovabaf6972006-01-18 17:42:46 -080024
25int is_skas_winch(int pid, int fd, void *data)
26{
Al Viro17e05202011-08-18 20:08:19 +010027 return pid == getpgrp();
Gennady Sharapovabaf6972006-01-18 17:42:46 -080028}
29
Jeff Dikef30c2c92007-05-06 14:51:29 -070030static int ptrace_dump_regs(int pid)
31{
Jeff Dike3e6f2ac2008-02-04 22:30:58 -080032 unsigned long regs[MAX_REG_NR];
33 int i;
Jeff Dikef30c2c92007-05-06 14:51:29 -070034
Jeff Dike3e6f2ac2008-02-04 22:30:58 -080035 if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
36 return -errno;
Jeff Dikeba180fd2007-10-16 01:27:00 -070037
38 printk(UM_KERN_ERR "Stub registers -\n");
39 for (i = 0; i < ARRAY_SIZE(regs); i++)
40 printk(UM_KERN_ERR "\t%d - %lx\n", i, regs[i]);
Jeff Dikef30c2c92007-05-06 14:51:29 -070041
Jeff Dike3e6f2ac2008-02-04 22:30:58 -080042 return 0;
Jeff Dikef30c2c92007-05-06 14:51:29 -070043}
44
Jeff Dike16dd07b2007-05-06 14:51:48 -070045/*
46 * Signals that are OK to receive in the stub - we'll just continue it.
47 * SIGWINCH will happen when UML is inside a detached screen.
48 */
Anton Ivanov2eb5f312015-11-02 16:16:37 +000049#define STUB_SIG_MASK ((1 << SIGALRM) | (1 << SIGWINCH))
Jeff Dike16dd07b2007-05-06 14:51:48 -070050
51/* Signals that the stub will finish with - anything else is an error */
Jeff Dikeee3d9bd2008-02-04 22:30:56 -080052#define STUB_DONE_MASK (1 << SIGTRAP)
Jeff Dike16dd07b2007-05-06 14:51:48 -070053
54void wait_stub_done(int pid)
Gennady Sharapovabaf6972006-01-18 17:42:46 -080055{
Richard Weinbergerae5db6d2014-07-20 12:56:34 +020056 int n, status, err;
Gennady Sharapovabaf6972006-01-18 17:42:46 -080057
Jeff Dikeba180fd2007-10-16 01:27:00 -070058 while (1) {
Stanislaw Gruszka4dbed852007-12-17 16:19:46 -080059 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL));
Jeff Dikeba180fd2007-10-16 01:27:00 -070060 if ((n < 0) || !WIFSTOPPED(status))
Jeff Dike16dd07b2007-05-06 14:51:48 -070061 goto bad_wait;
Gennady Sharapovabaf6972006-01-18 17:42:46 -080062
Jeff Dikeba180fd2007-10-16 01:27:00 -070063 if (((1 << WSTOPSIG(status)) & STUB_SIG_MASK) == 0)
Jeff Dike16dd07b2007-05-06 14:51:48 -070064 break;
65
66 err = ptrace(PTRACE_CONT, pid, 0, 0);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -080067 if (err) {
68 printk(UM_KERN_ERR "wait_stub_done : continue failed, "
69 "errno = %d\n", errno);
70 fatal_sigsegv();
71 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -080072 }
Jeff Dike16dd07b2007-05-06 14:51:48 -070073
Jeff Dikeba180fd2007-10-16 01:27:00 -070074 if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0)
Jeff Dike16dd07b2007-05-06 14:51:48 -070075 return;
76
77bad_wait:
78 err = ptrace_dump_regs(pid);
Jeff Dikeba180fd2007-10-16 01:27:00 -070079 if (err)
80 printk(UM_KERN_ERR "Failed to get registers from stub, "
81 "errno = %d\n", -err);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -080082 printk(UM_KERN_ERR "wait_stub_done : failed to wait for SIGTRAP, "
83 "pid = %d, n = %d, errno = %d, status = 0x%x\n", pid, n, errno,
84 status);
Richard Weinbergerae5db6d2014-07-20 12:56:34 +020085 fatal_sigsegv();
Gennady Sharapovabaf6972006-01-18 17:42:46 -080086}
87
88extern unsigned long current_stub_stack(void);
89
Thomas Meyer535d4c02017-07-29 17:03:23 +020090static void get_skas_faultinfo(int pid, struct faultinfo *fi, unsigned long *aux_fp_regs)
Gennady Sharapovabaf6972006-01-18 17:42:46 -080091{
92 int err;
93
Thomas Meyer535d4c02017-07-29 17:03:23 +020094 err = get_fp_registers(pid, aux_fp_regs);
Richard Weinbergerd0b5e152015-03-18 21:31:27 +010095 if (err < 0) {
96 printk(UM_KERN_ERR "save_fp_registers returned %d\n",
97 err);
98 fatal_sigsegv();
Gennady Sharapovabaf6972006-01-18 17:42:46 -080099 }
Richard Weinbergerd0b5e152015-03-18 21:31:27 +0100100 err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV);
101 if (err) {
102 printk(UM_KERN_ERR "Failed to continue stub, pid = %d, "
103 "errno = %d\n", pid, errno);
104 fatal_sigsegv();
105 }
106 wait_stub_done(pid);
Jeff Dike2f56deb2008-02-23 15:23:49 -0800107
Richard Weinbergerd0b5e152015-03-18 21:31:27 +0100108 /*
109 * faultinfo is prepared by the stub-segv-handler at start of
110 * the stub stack page. We just have to copy it.
111 */
112 memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800113
Thomas Meyer535d4c02017-07-29 17:03:23 +0200114 err = put_fp_registers(pid, aux_fp_regs);
Richard Weinbergerd0b5e152015-03-18 21:31:27 +0100115 if (err < 0) {
116 printk(UM_KERN_ERR "put_fp_registers returned %d\n",
117 err);
118 fatal_sigsegv();
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800119 }
120}
121
Thomas Meyer535d4c02017-07-29 17:03:23 +0200122static void handle_segv(int pid, struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800123{
Thomas Meyer535d4c02017-07-29 17:03:23 +0200124 get_skas_faultinfo(pid, &regs->faultinfo, aux_fp_regs);
Jeff Dike77bf4402007-10-16 01:26:58 -0700125 segv(regs->faultinfo, 0, 1, NULL);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800126}
127
Jeff Dikeba180fd2007-10-16 01:27:00 -0700128/*
129 * To use the same value of using_sysemu as the caller, ask it that value
130 * (in local_using_sysemu
131 */
132static void handle_trap(int pid, struct uml_pt_regs *regs,
133 int local_using_sysemu)
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800134{
135 int err, status;
136
Jeff Dikee06173b2008-02-04 22:31:12 -0800137 if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END))
138 fatal_sigsegv();
139
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800140 if (!local_using_sysemu)
141 {
Al Viro966e8032011-08-18 20:12:19 +0100142 err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800143 __NR_getpid);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800144 if (err < 0) {
145 printk(UM_KERN_ERR "handle_trap - nullifying syscall "
146 "failed, errno = %d\n", errno);
147 fatal_sigsegv();
148 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800149
Jeff Dikeba180fd2007-10-16 01:27:00 -0700150 err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800151 if (err < 0) {
152 printk(UM_KERN_ERR "handle_trap - continuing to end of "
153 "syscall failed, errno = %d\n", errno);
154 fatal_sigsegv();
155 }
Jeff Dikeba180fd2007-10-16 01:27:00 -0700156
Stanislaw Gruszka4dbed852007-12-17 16:19:46 -0800157 CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL));
Jeff Dikeba180fd2007-10-16 01:27:00 -0700158 if ((err < 0) || !WIFSTOPPED(status) ||
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800159 (WSTOPSIG(status) != SIGTRAP + 0x80)) {
160 err = ptrace_dump_regs(pid);
161 if (err)
162 printk(UM_KERN_ERR "Failed to get registers "
Jeff Dikeba180fd2007-10-16 01:27:00 -0700163 "from process, errno = %d\n", -err);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800164 printk(UM_KERN_ERR "handle_trap - failed to wait at "
165 "end of syscall, errno = %d, status = %d\n",
166 errno, status);
167 fatal_sigsegv();
168 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800169 }
170
171 handle_syscall(regs);
172}
173
Nicolas Iooss5f329432014-10-12 13:02:13 +0200174extern char __syscall_stub_start[];
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800175
176static int userspace_tramp(void *stack)
177{
178 void *addr;
Anton Ivanov2eb5f312015-11-02 16:16:37 +0000179 int fd;
Richard Weinbergerd0b5e152015-03-18 21:31:27 +0100180 unsigned long long offset;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800181
182 ptrace(PTRACE_TRACEME, 0, 0, 0);
183
Lepton Wua24864a2007-10-16 01:27:35 -0700184 signal(SIGTERM, SIG_DFL);
Jeff Dikeee3d9bd2008-02-04 22:30:56 -0800185 signal(SIGWINCH, SIG_IGN);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800186
Richard Weinbergerd0b5e152015-03-18 21:31:27 +0100187 /*
188 * This has a pte, but it can't be mapped in with the usual
189 * tlb_flush mechanism because this is part of that mechanism
190 */
Nicolas Iooss5f329432014-10-12 13:02:13 +0200191 fd = phys_mapping(to_phys(__syscall_stub_start), &offset);
Richard Weinbergerd0b5e152015-03-18 21:31:27 +0100192 addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE,
193 PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
194 if (addr == MAP_FAILED) {
195 printk(UM_KERN_ERR "mapping mmap stub at 0x%lx failed, "
196 "errno = %d\n", STUB_CODE, errno);
197 exit(1);
198 }
199
200 if (stack != NULL) {
201 fd = phys_mapping(to_phys(stack), &offset);
202 addr = mmap((void *) STUB_DATA,
203 UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
204 MAP_FIXED | MAP_SHARED, fd, offset);
Jeff Dikeba180fd2007-10-16 01:27:00 -0700205 if (addr == MAP_FAILED) {
Richard Weinbergerd0b5e152015-03-18 21:31:27 +0100206 printk(UM_KERN_ERR "mapping segfault stack "
207 "at 0x%lx failed, errno = %d\n",
208 STUB_DATA, errno);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800209 exit(1);
210 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800211 }
Richard Weinbergerd0b5e152015-03-18 21:31:27 +0100212 if (stack != NULL) {
Jeff Dike4b84c692006-09-25 23:33:04 -0700213 struct sigaction sa;
214
Jeff Dike54ae36f2007-10-16 01:27:33 -0700215 unsigned long v = STUB_CODE +
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800216 (unsigned long) stub_segv_handler -
Nicolas Iooss5f329432014-10-12 13:02:13 +0200217 (unsigned long) __syscall_stub_start;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800218
Jeff Dike54ae36f2007-10-16 01:27:33 -0700219 set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE);
Jeff Dike4b84c692006-09-25 23:33:04 -0700220 sigemptyset(&sa.sa_mask);
Al Viro9b25fcb2011-08-18 20:04:09 +0100221 sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO;
222 sa.sa_sigaction = (void *) v;
Jeff Dike4b84c692006-09-25 23:33:04 -0700223 sa.sa_restorer = NULL;
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800224 if (sigaction(SIGSEGV, &sa, NULL) < 0) {
225 printk(UM_KERN_ERR "userspace_tramp - setting SIGSEGV "
226 "handler failed - errno = %d\n", errno);
227 exit(1);
228 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800229 }
230
Jeff Dike512b6fb2007-10-16 01:27:11 -0700231 kill(os_getpid(), SIGSTOP);
Jeff Dikeba180fd2007-10-16 01:27:00 -0700232 return 0;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800233}
234
235/* Each element set once, and only accessed by a single processor anyway */
236#undef NR_CPUS
237#define NR_CPUS 1
238int userspace_pid[NR_CPUS];
239
240int start_userspace(unsigned long stub_stack)
241{
242 void *stack;
243 unsigned long sp;
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800244 int pid, status, n, flags, err;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800245
Jeff Dikec539ab72007-06-16 10:16:09 -0700246 stack = mmap(NULL, UM_KERN_PAGE_SIZE,
247 PROT_READ | PROT_WRITE | PROT_EXEC,
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800248 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800249 if (stack == MAP_FAILED) {
250 err = -errno;
251 printk(UM_KERN_ERR "start_userspace : mmap failed, "
Jeff Dikeb5498832008-02-04 22:31:21 -0800252 "errno = %d\n", errno);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800253 return err;
254 }
255
Jeff Dikec539ab72007-06-16 10:16:09 -0700256 sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800257
Richard Weinbergerd0b5e152015-03-18 21:31:27 +0100258 flags = CLONE_FILES | SIGCHLD;
Jeff Dikeba180fd2007-10-16 01:27:00 -0700259
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800260 pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800261 if (pid < 0) {
262 err = -errno;
263 printk(UM_KERN_ERR "start_userspace : clone failed, "
Jeff Dikeb5498832008-02-04 22:31:21 -0800264 "errno = %d\n", errno);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800265 return err;
266 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800267
268 do {
Stanislaw Gruszka4dbed852007-12-17 16:19:46 -0800269 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL));
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800270 if (n < 0) {
271 err = -errno;
272 printk(UM_KERN_ERR "start_userspace : wait failed, "
Jeff Dikeb5498832008-02-04 22:31:21 -0800273 "errno = %d\n", errno);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800274 goto out_kill;
275 }
Anton Ivanov2eb5f312015-11-02 16:16:37 +0000276 } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGALRM));
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800277
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800278 if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) {
279 err = -EINVAL;
280 printk(UM_KERN_ERR "start_userspace : expected SIGSTOP, got "
Jeff Dikeb5498832008-02-04 22:31:21 -0800281 "status = %d\n", status);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800282 goto out_kill;
283 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800284
Jeff Dikeba180fd2007-10-16 01:27:00 -0700285 if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800286 (void *) PTRACE_O_TRACESYSGOOD) < 0) {
287 err = -errno;
288 printk(UM_KERN_ERR "start_userspace : PTRACE_OLDSETOPTIONS "
289 "failed, errno = %d\n", errno);
290 goto out_kill;
291 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800292
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800293 if (munmap(stack, UM_KERN_PAGE_SIZE) < 0) {
294 err = -errno;
295 printk(UM_KERN_ERR "start_userspace : munmap failed, "
296 "errno = %d\n", errno);
297 goto out_kill;
298 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800299
Jeff Dikeba180fd2007-10-16 01:27:00 -0700300 return pid;
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800301
302 out_kill:
303 os_kill_ptraced_process(pid, 1);
304 return err;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800305}
306
Thomas Meyer535d4c02017-07-29 17:03:23 +0200307void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800308{
309 int err, status, op, pid = userspace_pid[0];
Jeff Dike2ea5bc52007-05-10 22:22:32 -0700310 /* To prevent races if using_sysemu changes under us.*/
311 int local_using_sysemu;
Martin Pärteld3c1cfc2012-08-02 00:49:17 +0200312 siginfo_t si;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800313
Al Virob8a42092012-05-23 00:25:15 -0400314 /* Handle any immediate reschedules or signals */
315 interrupt_end();
316
Jeff Dikeba180fd2007-10-16 01:27:00 -0700317 while (1) {
Anton Ivanov2eb5f312015-11-02 16:16:37 +0000318
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800319 /*
320 * This can legitimately fail if the process loads a
321 * bogus value into a segment register. It will
322 * segfault and PTRACE_GETREGS will read that value
323 * out of the process. However, PTRACE_SETREGS will
324 * fail. In this case, there is nothing to do but
325 * just kill the process.
326 */
Jeff Diked25f2e12008-02-04 22:30:57 -0800327 if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp))
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800328 fatal_sigsegv();
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800329
Ingo van Lilfbfe9c82011-09-14 16:21:23 -0700330 if (put_fp_registers(pid, regs->fp))
331 fatal_sigsegv();
332
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800333 /* Now we set local_using_sysemu to be used for one loop */
334 local_using_sysemu = get_using_sysemu();
335
Jeff Dike2ea5bc52007-05-10 22:22:32 -0700336 op = SELECT_PTRACE_OPERATION(local_using_sysemu,
337 singlestepping(NULL));
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800338
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800339 if (ptrace(op, pid, 0, 0)) {
340 printk(UM_KERN_ERR "userspace - ptrace continue "
341 "failed, op = %d, errno = %d\n", op, errno);
342 fatal_sigsegv();
343 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800344
Stanislaw Gruszka4dbed852007-12-17 16:19:46 -0800345 CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL));
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800346 if (err < 0) {
347 printk(UM_KERN_ERR "userspace - wait failed, "
348 "errno = %d\n", errno);
349 fatal_sigsegv();
350 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800351
Jeff Dike77bf4402007-10-16 01:26:58 -0700352 regs->is_user = 1;
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800353 if (ptrace(PTRACE_GETREGS, pid, 0, regs->gp)) {
354 printk(UM_KERN_ERR "userspace - PTRACE_GETREGS failed, "
355 "errno = %d\n", errno);
356 fatal_sigsegv();
357 }
Jeff Diked25f2e12008-02-04 22:30:57 -0800358
Ingo van Lilfbfe9c82011-09-14 16:21:23 -0700359 if (get_fp_registers(pid, regs->fp)) {
360 printk(UM_KERN_ERR "userspace - get_fp_registers failed, "
361 "errno = %d\n", errno);
362 fatal_sigsegv();
363 }
364
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800365 UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
366
Jeff Dikeba180fd2007-10-16 01:27:00 -0700367 if (WIFSTOPPED(status)) {
Jeff Dike16dd07b2007-05-06 14:51:48 -0700368 int sig = WSTOPSIG(status);
Martin Pärteld3c1cfc2012-08-02 00:49:17 +0200369
Richard Weinberger9a8c1352013-07-19 11:31:36 +0200370 ptrace(PTRACE_GETSIGINFO, pid, 0, (struct siginfo *)&si);
Martin Pärteld3c1cfc2012-08-02 00:49:17 +0200371
Jeff Dike5134d8f2008-02-08 04:22:08 -0800372 switch (sig) {
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800373 case SIGSEGV:
Richard Weinbergerd0b5e152015-03-18 21:31:27 +0100374 if (PTRACE_FULL_FAULTINFO) {
Jeff Dikeba180fd2007-10-16 01:27:00 -0700375 get_skas_faultinfo(pid,
Thomas Meyer535d4c02017-07-29 17:03:23 +0200376 &regs->faultinfo, aux_fp_regs);
Richard Weinberger9a8c1352013-07-19 11:31:36 +0200377 (*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si,
Martin Pärteld3c1cfc2012-08-02 00:49:17 +0200378 regs);
Jeff Dike16dd07b2007-05-06 14:51:48 -0700379 }
Thomas Meyer535d4c02017-07-29 17:03:23 +0200380 else handle_segv(pid, regs, aux_fp_regs);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800381 break;
382 case SIGTRAP + 0x80:
383 handle_trap(pid, regs, local_using_sysemu);
384 break;
385 case SIGTRAP:
Richard Weinberger9a8c1352013-07-19 11:31:36 +0200386 relay_signal(SIGTRAP, (struct siginfo *)&si, regs);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800387 break;
Anton Ivanov2eb5f312015-11-02 16:16:37 +0000388 case SIGALRM:
Jeff Diked2753a6d2007-10-16 01:27:25 -0700389 break;
390 case SIGIO:
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800391 case SIGILL:
392 case SIGBUS:
393 case SIGFPE:
394 case SIGWINCH:
Jeff Dike16dd07b2007-05-06 14:51:48 -0700395 block_signals();
Richard Weinberger9a8c1352013-07-19 11:31:36 +0200396 (*sig_info[sig])(sig, (struct siginfo *)&si, regs);
Jeff Dike16dd07b2007-05-06 14:51:48 -0700397 unblock_signals();
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800398 break;
399 default:
Jeff Dike96cee302008-05-12 14:01:48 -0700400 printk(UM_KERN_ERR "userspace - child stopped "
Jeff Dikeba180fd2007-10-16 01:27:00 -0700401 "with signal %d\n", sig);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800402 fatal_sigsegv();
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800403 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800404 pid = userspace_pid[0];
405 interrupt_end();
406
407 /* Avoid -ERESTARTSYS handling in host */
Jeff Dikeba180fd2007-10-16 01:27:00 -0700408 if (PT_SYSCALL_NR_OFFSET != PT_SYSCALL_RET_OFFSET)
Jeff Dike18baddd2007-10-16 01:27:07 -0700409 PT_SYSCALL_NR(regs->gp) = -1;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800410 }
411 }
412}
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800413
Jeff Dike16dd07b2007-05-06 14:51:48 -0700414static unsigned long thread_regs[MAX_REG_NR];
Ingo van Lilfbfe9c82011-09-14 16:21:23 -0700415static unsigned long thread_fp_regs[FP_SIZE];
Jeff Dike16dd07b2007-05-06 14:51:48 -0700416
417static int __init init_thread_regs(void)
418{
Ingo van Lilfbfe9c82011-09-14 16:21:23 -0700419 get_safe_registers(thread_regs, thread_fp_regs);
Jeff Dike16dd07b2007-05-06 14:51:48 -0700420 /* Set parent's instruction pointer to start of clone-stub */
Jeff Dike54ae36f2007-10-16 01:27:33 -0700421 thread_regs[REGS_IP_INDEX] = STUB_CODE +
Jeff Dike16dd07b2007-05-06 14:51:48 -0700422 (unsigned long) stub_clone_handler -
Nicolas Iooss5f329432014-10-12 13:02:13 +0200423 (unsigned long) __syscall_stub_start;
Jeff Dike54ae36f2007-10-16 01:27:33 -0700424 thread_regs[REGS_SP_INDEX] = STUB_DATA + UM_KERN_PAGE_SIZE -
Jeff Dike16dd07b2007-05-06 14:51:48 -0700425 sizeof(void *);
426#ifdef __SIGNAL_FRAMESIZE
427 thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE;
428#endif
429 return 0;
430}
431
432__initcall(init_thread_regs);
433
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800434int copy_context_skas0(unsigned long new_stack, int pid)
435{
436 int err;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800437 unsigned long current_stack = current_stub_stack();
438 struct stub_data *data = (struct stub_data *) current_stack;
439 struct stub_data *child_data = (struct stub_data *) new_stack;
Jeff Dike0a7675a2007-10-16 01:27:05 -0700440 unsigned long long new_offset;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800441 int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset);
442
Jeff Dikeba180fd2007-10-16 01:27:00 -0700443 /*
444 * prepare offset and fd of child's stack as argument for parent's
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800445 * and child's mmap2 calls
446 */
Anton Ivanov2eb5f312015-11-02 16:16:37 +0000447 *data = ((struct stub_data) {
448 .offset = MMAP_OFFSET(new_offset),
449 .fd = new_fd
450 });
Jeff Diked2753a6d2007-10-16 01:27:25 -0700451
Jeff Dike16dd07b2007-05-06 14:51:48 -0700452 err = ptrace_setregs(pid, thread_regs);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800453 if (err < 0) {
454 err = -errno;
455 printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_SETREGS "
456 "failed, pid = %d, errno = %d\n", pid, -err);
457 return err;
458 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800459
Ingo van Lilfbfe9c82011-09-14 16:21:23 -0700460 err = put_fp_registers(pid, thread_fp_regs);
461 if (err < 0) {
462 printk(UM_KERN_ERR "copy_context_skas0 : put_fp_registers "
463 "failed, pid = %d, err = %d\n", pid, err);
464 return err;
465 }
466
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800467 /* set a well known return code for detection of child write failure */
468 child_data->err = 12345678;
469
Jeff Dikeba180fd2007-10-16 01:27:00 -0700470 /*
471 * Wait, until parent has finished its work: read child's pid from
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800472 * parent's stack, and check, if bad result.
473 */
Jeff Dike16dd07b2007-05-06 14:51:48 -0700474 err = ptrace(PTRACE_CONT, pid, 0, 0);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800475 if (err) {
476 err = -errno;
477 printk(UM_KERN_ERR "Failed to continue new process, pid = %d, "
478 "errno = %d\n", pid, errno);
479 return err;
480 }
481
Jeff Dike16dd07b2007-05-06 14:51:48 -0700482 wait_stub_done(pid);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800483
484 pid = data->err;
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800485 if (pid < 0) {
486 printk(UM_KERN_ERR "copy_context_skas0 - stub-parent reports "
487 "error %d\n", -pid);
488 return pid;
489 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800490
Jeff Dikeba180fd2007-10-16 01:27:00 -0700491 /*
492 * Wait, until child has finished too: read child's result from
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800493 * child's stack and check it.
494 */
Jeff Dike16dd07b2007-05-06 14:51:48 -0700495 wait_stub_done(pid);
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800496 if (child_data->err != STUB_DATA) {
497 printk(UM_KERN_ERR "copy_context_skas0 - stub-child reports "
498 "error %ld\n", child_data->err);
499 err = child_data->err;
500 goto out_kill;
501 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800502
503 if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800504 (void *)PTRACE_O_TRACESYSGOOD) < 0) {
505 err = -errno;
506 printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_OLDSETOPTIONS "
507 "failed, errno = %d\n", errno);
508 goto out_kill;
509 }
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800510
511 return pid;
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800512
513 out_kill:
514 os_kill_ptraced_process(pid, 1);
515 return err;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800516}
517
Jeff Dike3c917352006-09-27 01:50:40 -0700518void new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800519{
Jeff Dike3c917352006-09-27 01:50:40 -0700520 (*buf)[0].JB_IP = (unsigned long) handler;
Jeff Dikee1a79c42007-05-10 22:22:31 -0700521 (*buf)[0].JB_SP = (unsigned long) stack + UM_THREAD_SIZE -
522 sizeof(void *);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800523}
524
Jeff Dikee2216fe2006-02-07 12:58:43 -0800525#define INIT_JMP_NEW_THREAD 0
Jeff Dike3c917352006-09-27 01:50:40 -0700526#define INIT_JMP_CALLBACK 1
527#define INIT_JMP_HALT 2
528#define INIT_JMP_REBOOT 3
Jeff Dikee2216fe2006-02-07 12:58:43 -0800529
Jeff Dike3c917352006-09-27 01:50:40 -0700530void switch_threads(jmp_buf *me, jmp_buf *you)
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800531{
Jeff Dikeba180fd2007-10-16 01:27:00 -0700532 if (UML_SETJMP(me) == 0)
Jeff Dike3c917352006-09-27 01:50:40 -0700533 UML_LONGJMP(you, 1);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800534}
535
Jeff Dikead28e022006-04-18 22:21:41 -0700536static jmp_buf initial_jmpbuf;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800537
538/* XXX Make these percpu */
539static void (*cb_proc)(void *arg);
540static void *cb_arg;
Jeff Dikead28e022006-04-18 22:21:41 -0700541static jmp_buf *cb_back;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800542
Jeff Dike3c917352006-09-27 01:50:40 -0700543int start_idle_thread(void *stack, jmp_buf *switch_buf)
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800544{
Jeff Dikea5df0d12006-07-14 00:24:02 -0700545 int n;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800546
Al Viro00361682011-08-18 20:04:39 +0100547 set_handler(SIGWINCH);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800548
Jeff Dike77f6af72007-05-06 14:51:40 -0700549 /*
550 * Can't use UML_SETJMP or UML_LONGJMP here because they save
551 * and restore signals, with the possible side-effect of
552 * trying to handle any signals which came when they were
553 * blocked, which can't be done on this stack.
554 * Signals must be blocked when jumping back here and restored
555 * after returning to the jumper.
556 */
557 n = setjmp(initial_jmpbuf);
Jeff Dike5134d8f2008-02-08 04:22:08 -0800558 switch (n) {
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800559 case INIT_JMP_NEW_THREAD:
Thomas Meyer33bbc302015-03-28 09:59:46 +0100560 (*switch_buf)[0].JB_IP = (unsigned long) uml_finishsetup;
Jeff Dike3c917352006-09-27 01:50:40 -0700561 (*switch_buf)[0].JB_SP = (unsigned long) stack +
Jeff Dikee1a79c42007-05-10 22:22:31 -0700562 UM_THREAD_SIZE - sizeof(void *);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800563 break;
564 case INIT_JMP_CALLBACK:
565 (*cb_proc)(cb_arg);
Jeff Dike77f6af72007-05-06 14:51:40 -0700566 longjmp(*cb_back, 1);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800567 break;
568 case INIT_JMP_HALT:
569 kmalloc_ok = 0;
Jeff Dikeba180fd2007-10-16 01:27:00 -0700570 return 0;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800571 case INIT_JMP_REBOOT:
572 kmalloc_ok = 0;
Jeff Dikeba180fd2007-10-16 01:27:00 -0700573 return 1;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800574 default:
Jeff Dike3e6f2ac2008-02-04 22:30:58 -0800575 printk(UM_KERN_ERR "Bad sigsetjmp return in "
576 "start_idle_thread - %d\n", n);
577 fatal_sigsegv();
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800578 }
Jeff Dike77f6af72007-05-06 14:51:40 -0700579 longjmp(*switch_buf, 1);
Richard Weinberger11832f32018-06-15 16:42:56 +0200580
581 /* unreachable */
582 printk(UM_KERN_ERR "impossible long jump!");
583 fatal_sigsegv();
584 return 0;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800585}
586
587void initial_thread_cb_skas(void (*proc)(void *), void *arg)
588{
Jeff Dikead28e022006-04-18 22:21:41 -0700589 jmp_buf here;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800590
591 cb_proc = proc;
592 cb_arg = arg;
593 cb_back = &here;
594
595 block_signals();
Jeff Dikeba180fd2007-10-16 01:27:00 -0700596 if (UML_SETJMP(&here) == 0)
Jeff Dikead28e022006-04-18 22:21:41 -0700597 UML_LONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800598 unblock_signals();
599
600 cb_proc = NULL;
601 cb_arg = NULL;
602 cb_back = NULL;
603}
604
605void halt_skas(void)
606{
607 block_signals();
Jeff Dikead28e022006-04-18 22:21:41 -0700608 UML_LONGJMP(&initial_jmpbuf, INIT_JMP_HALT);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800609}
610
611void reboot_skas(void)
612{
613 block_signals();
Jeff Dikead28e022006-04-18 22:21:41 -0700614 UML_LONGJMP(&initial_jmpbuf, INIT_JMP_REBOOT);
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800615}
616
Jeff Dike77bf4402007-10-16 01:26:58 -0700617void __switch_mm(struct mm_id *mm_idp)
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800618{
Richard Weinbergerd0b5e152015-03-18 21:31:27 +0100619 userspace_pid[0] = mm_idp->u.pid;
Gennady Sharapovabaf6972006-01-18 17:42:46 -0800620}