Merge tag 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm
[sfrench/cifs-2.6.git] / arch / um / os-Linux / start_up.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdarg.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <sched.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <sys/mman.h>
16 #include <sys/stat.h>
17 #include <sys/wait.h>
18 #include <sys/time.h>
19 #include <sys/resource.h>
20 #include <asm/unistd.h>
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>
27
28 static void ptrace_child(void)
29 {
30         int ret;
31         /* Calling os_getpid because some libcs cached getpid incorrectly */
32         int pid = os_getpid(), ppid = getppid();
33         int sc_result;
34
35         if (change_sig(SIGWINCH, 0) < 0 ||
36             ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
37                 perror("ptrace");
38                 kill(pid, SIGKILL);
39         }
40         kill(pid, SIGSTOP);
41
42         /*
43          * This syscall will be intercepted by the parent. Don't call more than
44          * once, please.
45          */
46         sc_result = os_getpid();
47
48         if (sc_result == pid)
49                 /* Nothing modified by the parent, we are running normally. */
50                 ret = 1;
51         else if (sc_result == ppid)
52                 /*
53                  * Expected in check_ptrace and check_sysemu when they succeed
54                  * in modifying the stack frame
55                  */
56                 ret = 0;
57         else
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;
63
64         exit(ret);
65 }
66
67 static void fatal_perror(const char *str)
68 {
69         perror(str);
70         exit(1);
71 }
72
73 static void fatal(char *fmt, ...)
74 {
75         va_list list;
76
77         va_start(list, fmt);
78         vfprintf(stderr, fmt, list);
79         va_end(list);
80
81         exit(1);
82 }
83
84 static void non_fatal(char *fmt, ...)
85 {
86         va_list list;
87
88         va_start(list, fmt);
89         vfprintf(stderr, fmt, list);
90         va_end(list);
91 }
92
93 static int start_ptraced_child(void)
94 {
95         int pid, n, status;
96
97         fflush(stdout);
98
99         pid = fork();
100         if (pid == 0)
101                 ptrace_child();
102         else if (pid < 0)
103                 fatal_perror("start_ptraced_child : fork failed");
104
105         CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
106         if (n < 0)
107                 fatal_perror("check_ptrace : waitpid failed");
108         if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
109                 fatal("check_ptrace : expected SIGSTOP, got status = %d",
110                       status);
111
112         return pid;
113 }
114
115 static void stop_ptraced_child(int pid, int exitcode)
116 {
117         int status, n;
118
119         if (ptrace(PTRACE_CONT, pid, 0, 0) < 0)
120                 fatal_perror("stop_ptraced_child : ptrace failed");
121
122         CATCH_EINTR(n = waitpid(pid, &status, 0));
123         if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
124                 int exit_with = WEXITSTATUS(status);
125                 fatal("stop_ptraced_child : child exited with exitcode %d, "
126                       "while expecting %d; status 0x%x\n", exit_with,
127                       exitcode, status);
128         }
129 }
130
131 static void __init check_sysemu(void)
132 {
133         int pid, n, status, count=0;
134
135         os_info("Checking syscall emulation for ptrace...");
136         pid = start_ptraced_child();
137
138         if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
139                    (void *) PTRACE_O_TRACESYSGOOD) < 0))
140                 fatal_perror("check_sysemu: PTRACE_SETOPTIONS failed");
141
142         while (1) {
143                 count++;
144                 if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
145                         goto fail;
146                 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
147                 if (n < 0)
148                         fatal_perror("check_sysemu: wait failed");
149
150                 if (WIFSTOPPED(status) &&
151                     (WSTOPSIG(status) == (SIGTRAP|0x80))) {
152                         if (!count) {
153                                 non_fatal("check_sysemu: SYSEMU_SINGLESTEP "
154                                           "doesn't singlestep");
155                                 goto fail;
156                         }
157                         n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET,
158                                    os_getpid());
159                         if (n < 0)
160                                 fatal_perror("check_sysemu : failed to modify "
161                                              "system call return");
162                         break;
163                 }
164                 else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP))
165                         count++;
166                 else {
167                         non_fatal("check_sysemu: expected SIGTRAP or "
168                                   "(SIGTRAP | 0x80), got status = %d\n",
169                                   status);
170                         goto fail;
171                 }
172         }
173         stop_ptraced_child(pid, 0);
174
175         os_info("OK\n");
176
177         return;
178
179 fail:
180         stop_ptraced_child(pid, 1);
181         fatal("missing\n");
182 }
183
184 static void __init check_ptrace(void)
185 {
186         int pid, syscall, n, status;
187
188         os_info("Checking that ptrace can change system call numbers...");
189         pid = start_ptraced_child();
190
191         if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
192                    (void *) PTRACE_O_TRACESYSGOOD) < 0))
193                 fatal_perror("check_ptrace: PTRACE_SETOPTIONS failed");
194
195         while (1) {
196                 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
197                         fatal_perror("check_ptrace : ptrace failed");
198
199                 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
200                 if (n < 0)
201                         fatal_perror("check_ptrace : wait failed");
202
203                 if (!WIFSTOPPED(status) ||
204                    (WSTOPSIG(status) != (SIGTRAP | 0x80)))
205                         fatal("check_ptrace : expected (SIGTRAP|0x80), "
206                                "got status = %d", status);
207
208                 syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
209                                  0);
210                 if (syscall == __NR_getpid) {
211                         n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
212                                    __NR_getppid);
213                         if (n < 0)
214                                 fatal_perror("check_ptrace : failed to modify "
215                                              "system call");
216                         break;
217                 }
218         }
219         stop_ptraced_child(pid, 0);
220         os_info("OK\n");
221         check_sysemu();
222 }
223
224 extern void check_tmpexec(void);
225
226 static void __init check_coredump_limit(void)
227 {
228         struct rlimit lim;
229         int err = getrlimit(RLIMIT_CORE, &lim);
230
231         if (err) {
232                 perror("Getting core dump limit");
233                 return;
234         }
235
236         os_info("Core dump limits :\n\tsoft - ");
237         if (lim.rlim_cur == RLIM_INFINITY)
238                 os_info("NONE\n");
239         else
240                 os_info("%llu\n", (unsigned long long)lim.rlim_cur);
241
242         os_info("\thard - ");
243         if (lim.rlim_max == RLIM_INFINITY)
244                 os_info("NONE\n");
245         else
246                 os_info("%llu\n", (unsigned long long)lim.rlim_max);
247 }
248
249 void  __init get_host_cpu_features(
250                 void (*flags_helper_func)(char *line),
251                 void (*cache_helper_func)(char *line))
252 {
253         FILE *cpuinfo;
254         char *line = NULL;
255         size_t len = 0;
256         int done_parsing = 0;
257
258         cpuinfo = fopen("/proc/cpuinfo", "r");
259         if (cpuinfo == NULL) {
260                 os_info("Failed to get host CPU features\n");
261         } else {
262                 while ((getline(&line, &len, cpuinfo)) != -1) {
263                         if (strstr(line, "flags")) {
264                                 flags_helper_func(line);
265                                 done_parsing++;
266                         }
267                         if (strstr(line, "cache_alignment")) {
268                                 cache_helper_func(line);
269                                 done_parsing++;
270                         }
271                         free(line);
272                         line = NULL;
273                         if (done_parsing > 1)
274                                 break;
275                 }
276                 fclose(cpuinfo);
277         }
278 }
279
280
281 void __init os_early_checks(void)
282 {
283         int pid;
284
285         /* Print out the core dump limits early */
286         check_coredump_limit();
287
288         check_ptrace();
289
290         /* Need to check this early because mmapping happens before the
291          * kernel is running.
292          */
293         check_tmpexec();
294
295         pid = start_ptraced_child();
296         if (init_pid_registers(pid))
297                 fatal("Failed to initialize default registers");
298         stop_ptraced_child(pid, 1);
299 }
300
301 int __init parse_iomem(char *str, int *add)
302 {
303         struct iomem_region *new;
304         struct stat64 buf;
305         char *file, *driver;
306         int fd, size;
307
308         driver = str;
309         file = strchr(str,',');
310         if (file == NULL) {
311                 os_warn("parse_iomem : failed to parse iomem\n");
312                 goto out;
313         }
314         *file = '\0';
315         file++;
316         fd = open(file, O_RDWR, 0);
317         if (fd < 0) {
318                 perror("parse_iomem - Couldn't open io file");
319                 goto out;
320         }
321
322         if (fstat64(fd, &buf) < 0) {
323                 perror("parse_iomem - cannot stat_fd file");
324                 goto out_close;
325         }
326
327         new = malloc(sizeof(*new));
328         if (new == NULL) {
329                 perror("Couldn't allocate iomem_region struct");
330                 goto out_close;
331         }
332
333         size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
334
335         *new = ((struct iomem_region) { .next           = iomem_regions,
336                                         .driver         = driver,
337                                         .fd             = fd,
338                                         .size           = size,
339                                         .phys           = 0,
340                                         .virt           = 0 });
341         iomem_regions = new;
342         iomem_size += new->size + UM_KERN_PAGE_SIZE;
343
344         return 0;
345  out_close:
346         close(fd);
347  out:
348         return 1;
349 }