]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - arch/um/os-Linux/start_up.c
um: Use os_warn to print out pre-boot warning/error messages
[mirror_ubuntu-bionic-kernel.git] / arch / um / os-Linux / start_up.c
CommitLineData
60d339f6 1/*
ba180fd4 2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
1da177e4
LT
3 * Licensed under the GPL
4 */
5
6#include <stdio.h>
0f80bc85 7#include <stdlib.h>
ba180fd4 8#include <stdarg.h>
1da177e4 9#include <unistd.h>
1da177e4 10#include <errno.h>
ba180fd4
JD
11#include <fcntl.h>
12#include <sched.h>
13#include <signal.h>
14#include <string.h>
1da177e4 15#include <sys/mman.h>
ba180fd4
JD
16#include <sys/stat.h>
17#include <sys/wait.h>
fdfa4c95
ST
18#include <sys/time.h>
19#include <sys/resource.h>
1da177e4 20#include <asm/unistd.h>
37185b33
AV
21#include <init.h>
22#include <os.h>
23#include <mem_user.h>
24#include <ptrace_user.h>
25#include <registers.h>
26#include <skas.h>
1da177e4 27
626c59f5 28static void ptrace_child(void)
1da177e4
LT
29{
30 int ret;
512b6fb1 31 /* Calling os_getpid because some libcs cached getpid incorrectly */
1da177e4
LT
32 int pid = os_getpid(), ppid = getppid();
33 int sc_result;
34
626c59f5
WC
35 if (change_sig(SIGWINCH, 0) < 0 ||
36 ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
1da177e4 37 perror("ptrace");
512b6fb1 38 kill(pid, SIGKILL);
1da177e4 39 }
73c8f444 40 kill(pid, SIGSTOP);
1da177e4 41
ba180fd4
JD
42 /*
43 * This syscall will be intercepted by the parent. Don't call more than
44 * once, please.
45 */
1da177e4
LT
46 sc_result = os_getpid();
47
48 if (sc_result == pid)
ba180fd4
JD
49 /* Nothing modified by the parent, we are running normally. */
50 ret = 1;
1da177e4 51 else if (sc_result == ppid)
ba180fd4
JD
52 /*
53 * Expected in check_ptrace and check_sysemu when they succeed
54 * in modifying the stack frame
55 */
56 ret = 0;
1da177e4 57 else
ba180fd4
JD
58 /* Serious trouble! This could be caused by a bug in host 2.6
59 * SKAS3/2.6 patch before release -V6, together with a bug in
60 * the UML code itself.
61 */
62 ret = 2;
bf8fde78
JD
63
64 exit(ret);
1da177e4
LT
65}
66
c9a3072d 67static void fatal_perror(const char *str)
3a150e1d
JD
68{
69 perror(str);
70 exit(1);
71}
72
73static void fatal(char *fmt, ...)
74{
75 va_list list;
76
77 va_start(list, fmt);
626c59f5 78 vfprintf(stderr, fmt, list);
3a150e1d 79 va_end(list);
3a150e1d
JD
80
81 exit(1);
82}
83
84static void non_fatal(char *fmt, ...)
85{
86 va_list list;
87
88 va_start(list, fmt);
626c59f5 89 vfprintf(stderr, fmt, list);
3a150e1d 90 va_end(list);
3a150e1d
JD
91}
92
3cdaf455 93static int start_ptraced_child(void)
1da177e4 94{
1da177e4 95 int pid, n, status;
60d339f6 96
0754fb29
VN
97 fflush(stdout);
98
3cdaf455
JD
99 pid = fork();
100 if (pid == 0)
101 ptrace_child();
102 else if (pid < 0)
103 fatal_perror("start_ptraced_child : fork failed");
ba180fd4 104
1da177e4 105 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
ba180fd4 106 if (n < 0)
3cdaf455 107 fatal_perror("check_ptrace : waitpid failed");
ba180fd4 108 if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
3a150e1d 109 fatal("check_ptrace : expected SIGSTOP, got status = %d",
1da177e4
LT
110 status);
111
9eae9b13 112 return pid;
1da177e4
LT
113}
114
60d339f6
GS
115/* When testing for SYSEMU support, if it is one of the broken versions, we
116 * must just avoid using sysemu, not panic, but only if SYSEMU features are
117 * broken.
1da177e4 118 * So only for SYSEMU features we test mustpanic, while normal host features
60d339f6
GS
119 * must work anyway!
120 */
3cdaf455 121static int stop_ptraced_child(int pid, int exitcode, int mustexit)
1da177e4
LT
122{
123 int status, n, ret = 0;
124
f1ef9167
JD
125 if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) {
126 perror("stop_ptraced_child : ptrace failed");
127 return -1;
128 }
1da177e4 129 CATCH_EINTR(n = waitpid(pid, &status, 0));
ba180fd4 130 if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
1da177e4
LT
131 int exit_with = WEXITSTATUS(status);
132 if (exit_with == 2)
3a150e1d 133 non_fatal("check_ptrace : child exited with status 2. "
cf6acedb 134 "\nDisabling SYSEMU support.\n");
3a150e1d
JD
135 non_fatal("check_ptrace : child exited with exitcode %d, while "
136 "expecting %d; status 0x%x\n", exit_with,
137 exitcode, status);
138 if (mustexit)
139 exit(1);
1da177e4
LT
140 ret = -1;
141 }
142
1da177e4
LT
143 return ret;
144}
145
7242a400 146/* Changed only during early boot */
60d339f6
GS
147static int force_sysemu_disabled = 0;
148
1da177e4
LT
149static int __init nosysemu_cmd_param(char *str, int* add)
150{
151 force_sysemu_disabled = 1;
152 return 0;
153}
154
155__uml_setup("nosysemu", nosysemu_cmd_param,
60d339f6
GS
156"nosysemu\n"
157" Turns off syscall emulation patch for ptrace (SYSEMU) on.\n"
158" SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
159" behaviour of ptrace() and helps reducing host context switch rate.\n"
160" To make it working, you need a kernel patch for your host, too.\n"
161" See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n"
162" information.\n\n");
1da177e4
LT
163
164static void __init check_sysemu(void)
165{
cf6acedb 166 unsigned long regs[MAX_REG_NR];
9eae9b13 167 int pid, n, status, count=0;
1da177e4 168
d3878bb8 169 os_info("Checking syscall emulation patch for ptrace...");
1da177e4 170 sysemu_supported = 0;
3cdaf455 171 pid = start_ptraced_child();
1da177e4 172
ba180fd4 173 if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
1da177e4
LT
174 goto fail;
175
176 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
177 if (n < 0)
3a150e1d 178 fatal_perror("check_sysemu : wait failed");
ba180fd4 179 if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
f1ef9167 180 fatal("check_sysemu : expected SIGTRAP, got status = %d\n",
3a150e1d 181 status);
1da177e4 182
ba180fd4 183 if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
cf6acedb 184 fatal_perror("check_sysemu : PTRACE_GETREGS failed");
ba180fd4 185 if (PT_SYSCALL_NR(regs) != __NR_getpid) {
cf6acedb
JD
186 non_fatal("check_sysemu got system call number %d, "
187 "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid);
188 goto fail;
189 }
190
966e803a 191 n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid());
ba180fd4 192 if (n < 0) {
cf6acedb
JD
193 non_fatal("check_sysemu : failed to modify system call "
194 "return");
195 goto fail;
196 }
1da177e4 197
3cdaf455 198 if (stop_ptraced_child(pid, 0, 0) < 0)
1da177e4
LT
199 goto fail_stopped;
200
201 sysemu_supported = 1;
d3878bb8 202 os_info("OK\n");
1da177e4
LT
203 set_using_sysemu(!force_sysemu_disabled);
204
d3878bb8 205 os_info("Checking advanced syscall emulation patch for ptrace...");
3cdaf455 206 pid = start_ptraced_child();
f9dfefe4 207
ba180fd4 208 if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
3a150e1d 209 (void *) PTRACE_O_TRACESYSGOOD) < 0))
5062910a 210 fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed");
f9dfefe4 211
ba180fd4 212 while (1) {
1da177e4 213 count++;
ba180fd4 214 if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
1da177e4
LT
215 goto fail;
216 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
ba180fd4 217 if (n < 0)
5062910a 218 fatal_perror("check_sysemu: wait failed");
3a150e1d 219
ba180fd4
JD
220 if (WIFSTOPPED(status) &&
221 (WSTOPSIG(status) == (SIGTRAP|0x80))) {
f1ef9167 222 if (!count) {
5062910a 223 non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
f1ef9167
JD
224 "doesn't singlestep");
225 goto fail;
226 }
966e803a 227 n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
1da177e4 228 os_getpid());
ba180fd4 229 if (n < 0)
3a150e1d
JD
230 fatal_perror("check_sysemu : failed to modify "
231 "system call return");
1da177e4
LT
232 break;
233 }
ba180fd4 234 else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
f9dfefe4 235 count++;
f1ef9167 236 else {
5062910a 237 non_fatal("check_sysemu: expected SIGTRAP or "
f1ef9167
JD
238 "(SIGTRAP | 0x80), got status = %d\n",
239 status);
240 goto fail;
241 }
1da177e4 242 }
3cdaf455 243 if (stop_ptraced_child(pid, 0, 0) < 0)
1da177e4
LT
244 goto fail_stopped;
245
246 sysemu_supported = 2;
d3878bb8 247 os_info("OK\n");
1da177e4 248
ba180fd4 249 if (!force_sysemu_disabled)
1da177e4
LT
250 set_using_sysemu(sysemu_supported);
251 return;
252
253fail:
3cdaf455 254 stop_ptraced_child(pid, 1, 0);
1da177e4 255fail_stopped:
3a150e1d 256 non_fatal("missing\n");
1da177e4
LT
257}
258
60d339f6 259static void __init check_ptrace(void)
1da177e4 260{
1da177e4
LT
261 int pid, syscall, n, status;
262
d3878bb8 263 os_info("Checking that ptrace can change system call numbers...");
3cdaf455 264 pid = start_ptraced_child();
1da177e4 265
ba180fd4 266 if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
3a150e1d
JD
267 (void *) PTRACE_O_TRACESYSGOOD) < 0))
268 fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed");
1da177e4 269
ba180fd4
JD
270 while (1) {
271 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
3a150e1d
JD
272 fatal_perror("check_ptrace : ptrace failed");
273
1da177e4 274 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
ba180fd4 275 if (n < 0)
3a150e1d
JD
276 fatal_perror("check_ptrace : wait failed");
277
ba180fd4 278 if (!WIFSTOPPED(status) ||
3a150e1d
JD
279 (WSTOPSIG(status) != (SIGTRAP | 0x80)))
280 fatal("check_ptrace : expected (SIGTRAP|0x80), "
281 "got status = %d", status);
60d339f6 282
966e803a 283 syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
1da177e4 284 0);
ba180fd4 285 if (syscall == __NR_getpid) {
966e803a 286 n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
1da177e4 287 __NR_getppid);
ba180fd4 288 if (n < 0)
3a150e1d
JD
289 fatal_perror("check_ptrace : failed to modify "
290 "system call");
1da177e4
LT
291 break;
292 }
293 }
3cdaf455 294 stop_ptraced_child(pid, 0, 1);
d3878bb8 295 os_info("OK\n");
1da177e4
LT
296 check_sysemu();
297}
298
966a082f 299extern void check_tmpexec(void);
0f80bc85 300
36e45463 301static void __init check_coredump_limit(void)
1d94cda0
JD
302{
303 struct rlimit lim;
304 int err = getrlimit(RLIMIT_CORE, &lim);
305
ba180fd4 306 if (err) {
1d94cda0
JD
307 perror("Getting core dump limit");
308 return;
309 }
310
d3878bb8 311 os_info("Core dump limits :\n\tsoft - ");
ba180fd4 312 if (lim.rlim_cur == RLIM_INFINITY)
d3878bb8
MH
313 os_info("NONE\n");
314 else
315 os_info("%llu\n", (unsigned long long)lim.rlim_cur);
1d94cda0 316
d3878bb8 317 os_info("\thard - ");
ba180fd4 318 if (lim.rlim_max == RLIM_INFINITY)
d3878bb8
MH
319 os_info("NONE\n");
320 else
321 os_info("%llu\n", (unsigned long long)lim.rlim_max);
1d94cda0
JD
322}
323
36e45463 324void __init os_early_checks(void)
1da177e4 325{
576c013d
JD
326 int pid;
327
1d94cda0
JD
328 /* Print out the core dump limits early */
329 check_coredump_limit();
330
60d339f6 331 check_ptrace();
0f80bc85
JD
332
333 /* Need to check this early because mmapping happens before the
334 * kernel is running.
335 */
336 check_tmpexec();
576c013d
JD
337
338 pid = start_ptraced_child();
339 if (init_registers(pid))
340 fatal("Failed to initialize default registers");
341 stop_ptraced_child(pid, 1, 1);
1da177e4
LT
342}
343
0f80bc85
JD
344int __init parse_iomem(char *str, int *add)
345{
346 struct iomem_region *new;
73c8f444 347 struct stat64 buf;
0f80bc85 348 char *file, *driver;
73c8f444 349 int fd, size;
0f80bc85
JD
350
351 driver = str;
352 file = strchr(str,',');
ba180fd4 353 if (file == NULL) {
0936d4f3 354 os_warn("parse_iomem : failed to parse iomem\n");
0f80bc85
JD
355 goto out;
356 }
357 *file = '\0';
358 file++;
73c8f444 359 fd = open(file, O_RDWR, 0);
ba180fd4 360 if (fd < 0) {
512b6fb1 361 perror("parse_iomem - Couldn't open io file");
0f80bc85
JD
362 goto out;
363 }
364
ba180fd4 365 if (fstat64(fd, &buf) < 0) {
73c8f444 366 perror("parse_iomem - cannot stat_fd file");
0f80bc85
JD
367 goto out_close;
368 }
369
370 new = malloc(sizeof(*new));
ba180fd4 371 if (new == NULL) {
0f80bc85
JD
372 perror("Couldn't allocate iomem_region struct");
373 goto out_close;
374 }
375
73c8f444 376 size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
0f80bc85
JD
377
378 *new = ((struct iomem_region) { .next = iomem_regions,
379 .driver = driver,
380 .fd = fd,
381 .size = size,
382 .phys = 0,
383 .virt = 0 });
384 iomem_regions = new;
385 iomem_size += new->size + UM_KERN_PAGE_SIZE;
386
9eae9b13 387 return 0;
0f80bc85 388 out_close:
73c8f444 389 close(fd);
0f80bc85 390 out:
9eae9b13 391 return 1;
0f80bc85 392}