1/*
2 * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include <unistd.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <signal.h>
11#include <errno.h>
12#include <sys/resource.h>
13#include <sys/mman.h>
14#include <sys/user.h>
15#include <asm/page.h>
16#include "kern_util.h"
17#include "as-layout.h"
18#include "mem_user.h"
19#include "irq_user.h"
20#include "user.h"
21#include "init.h"
22#include "mode.h"
23#include "choose-mode.h"
24#include "uml-config.h"
25#include "os.h"
26#include "um_malloc.h"
27#include "kern_constants.h"
28
29/* Set in main, unchanged thereafter */
30char *linux_prog;
31
32#define PGD_BOUND (4 * 1024 * 1024)
33#define STACKSIZE (8 * 1024 * 1024)
34#define THREAD_NAME_LEN (256)
35
36static void set_stklim(void)
37{
38	struct rlimit lim;
39
40	if(getrlimit(RLIMIT_STACK, &lim) < 0){
41		perror("getrlimit");
42		exit(1);
43	}
44	if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){
45		lim.rlim_cur = STACKSIZE;
46		if(setrlimit(RLIMIT_STACK, &lim) < 0){
47			perror("setrlimit");
48			exit(1);
49		}
50	}
51}
52
53static __init void do_uml_initcalls(void)
54{
55	initcall_t *call;
56
57	call = &__uml_initcall_start;
58	while (call < &__uml_initcall_end){
59		(*call)();
60		call++;
61	}
62}
63
64static void last_ditch_exit(int sig)
65{
66	uml_cleanup();
67	exit(1);
68}
69
70static void install_fatal_handler(int sig)
71{
72	struct sigaction action;
73
74	/* All signals are enabled in this handler ... */
75	sigemptyset(&action.sa_mask);
76
77	/* ... including the signal being handled, plus we want the
78	 * handler reset to the default behavior, so that if an exit
79	 * handler is hanging for some reason, the UML will just die
80	 * after this signal is sent a second time.
81	 */
82	action.sa_flags = SA_RESETHAND | SA_NODEFER;
83	action.sa_restorer = NULL;
84	action.sa_handler = last_ditch_exit;
85	if(sigaction(sig, &action, NULL) < 0){
86		printf("failed to install handler for signal %d - errno = %d\n",
87		       errno);
88		exit(1);
89	}
90}
91
92#define UML_LIB_PATH	":/usr/lib/uml"
93
94static void setup_env_path(void)
95{
96	char *new_path = NULL;
97	char *old_path = NULL;
98	int path_len = 0;
99
100	old_path = getenv("PATH");
101	/* if no PATH variable is set or it has an empty value
102	 * just use the default + /usr/lib/uml
103	 */
104	if (!old_path || (path_len = strlen(old_path)) == 0) {
105		putenv("PATH=:/bin:/usr/bin/" UML_LIB_PATH);
106		return;
107	}
108
109	/* append /usr/lib/uml to the existing path */
110	path_len += strlen("PATH=" UML_LIB_PATH) + 1;
111	new_path = malloc(path_len);
112	if (!new_path) {
113		perror("coudn't malloc to set a new PATH");
114		return;
115	}
116	snprintf(new_path, path_len, "PATH=%s" UML_LIB_PATH, old_path);
117	putenv(new_path);
118}
119
120extern int uml_exitcode;
121
122extern void scan_elf_aux( char **envp);
123
124int __init main(int argc, char **argv, char **envp)
125{
126	char **new_argv;
127	int ret, i, err;
128
129#ifdef UML_CONFIG_CMDLINE_ON_HOST
130	/* Allocate memory for thread command lines */
131	if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
132
133		char padding[THREAD_NAME_LEN] = {
134			[ 0 ...  THREAD_NAME_LEN - 2] = ' ', '\0'
135		};
136
137		new_argv = malloc((argc + 2) * sizeof(char*));
138		if(!new_argv) {
139			perror("Allocating extended argv");
140			exit(1);
141		}
142
143		new_argv[0] = argv[0];
144		new_argv[1] = padding;
145
146		for(i = 2; i <= argc; i++)
147			new_argv[i] = argv[i - 1];
148		new_argv[argc + 1] = NULL;
149
150		execvp(new_argv[0], new_argv);
151		perror("execing with extended args");
152		exit(1);
153	}
154#endif
155
156	linux_prog = argv[0];
157
158	set_stklim();
159
160	setup_env_path();
161
162	new_argv = malloc((argc + 1) * sizeof(char *));
163	if(new_argv == NULL){
164		perror("Mallocing argv");
165		exit(1);
166	}
167	for(i=0;i<argc;i++){
168		new_argv[i] = strdup(argv[i]);
169		if(new_argv[i] == NULL){
170			perror("Mallocing an arg");
171			exit(1);
172		}
173	}
174	new_argv[argc] = NULL;
175
176	/* Allow these signals to bring down a UML if all other
177	 * methods of control fail.
178	 */
179	install_fatal_handler(SIGINT);
180	install_fatal_handler(SIGTERM);
181	install_fatal_handler(SIGHUP);
182
183	scan_elf_aux( envp);
184
185	do_uml_initcalls();
186	ret = linux_main(argc, argv);
187
188	/* Disable SIGPROF - I have no idea why libc doesn't do this or turn
189	 * off the profiling time, but UML dies with a SIGPROF just before
190	 * exiting when profiling is active.
191	 */
192	change_sig(SIGPROF, 0);
193
194	/* This signal stuff used to be in the reboot case.  However,
195	 * sometimes a SIGVTALRM can come in when we're halting (reproducably
196	 * when writing out gcov information, presumably because that takes
197	 * some time) and cause a segfault.
198	 */
199
200	/* stop timers and set SIG*ALRM to be ignored */
201	disable_timer();
202
203	/* disable SIGIO for the fds and set SIGIO to be ignored */
204	err = deactivate_all_fds();
205	if(err)
206		printf("deactivate_all_fds failed, errno = %d\n", -err);
207
208	/* Let any pending signals fire now.  This ensures
209	 * that they won't be delivered after the exec, when
210	 * they are definitely not expected.
211	 */
212	unblock_signals();
213
214	/* Reboot */
215	if(ret){
216		printf("\n");
217		execvp(new_argv[0], new_argv);
218		perror("Failed to exec kernel");
219		ret = 1;
220	}
221	printf("\n");
222	return uml_exitcode;
223}
224
225#define CAN_KMALLOC() \
226	(kmalloc_ok && CHOOSE_MODE((os_getpid() != tracing_pid), 1))
227
228extern void *__real_malloc(int);
229
230void *__wrap_malloc(int size)
231{
232	void *ret;
233
234	if(!CAN_KMALLOC())
235		return __real_malloc(size);
236	else if(size <= UM_KERN_PAGE_SIZE)
237		/* finding contiguous pages can be hard*/
238		ret = um_kmalloc(size);
239	else ret = um_vmalloc(size);
240
241	/* glibc people insist that if malloc fails, errno should be
242	 * set by malloc as well. So we do.
243	 */
244	if(ret == NULL)
245		errno = ENOMEM;
246
247	return ret;
248}
249
250void *__wrap_calloc(int n, int size)
251{
252	void *ptr = __wrap_malloc(n * size);
253
254	if(ptr == NULL)
255		return NULL;
256	memset(ptr, 0, n * size);
257	return ptr;
258}
259
260extern void __real_free(void *);
261
262extern unsigned long high_physmem;
263
264void __wrap_free(void *ptr)
265{
266	unsigned long addr = (unsigned long) ptr;
267
268
269	if((addr >= uml_physmem) && (addr < high_physmem)){
270		if(CAN_KMALLOC())
271			kfree(ptr);
272	}
273	else if((addr >= start_vm) && (addr < end_vm)){
274		if(CAN_KMALLOC())
275			vfree(ptr);
276	}
277	else __real_free(ptr);
278}
279