1/*
2 * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/kernel.h"
7#include "linux/sched.h"
8#include "linux/notifier.h"
9#include "linux/mm.h"
10#include "linux/types.h"
11#include "linux/tty.h"
12#include "linux/init.h"
13#include "linux/bootmem.h"
14#include "linux/spinlock.h"
15#include "linux/utsname.h"
16#include "linux/sysrq.h"
17#include "linux/seq_file.h"
18#include "linux/delay.h"
19#include "linux/module.h"
20#include "linux/utsname.h"
21#include "asm/page.h"
22#include "asm/pgtable.h"
23#include "asm/ptrace.h"
24#include "asm/elf.h"
25#include "asm/user.h"
26#include "asm/setup.h"
27#include "ubd_user.h"
28#include "asm/current.h"
29#include "kern_util.h"
30#include "as-layout.h"
31#include "arch.h"
32#include "kern.h"
33#include "mem_user.h"
34#include "mem.h"
35#include "initrd.h"
36#include "init.h"
37#include "os.h"
38#include "choose-mode.h"
39#include "mode_kern.h"
40#include "mode.h"
41#ifdef UML_CONFIG_MODE_SKAS
42#include "skas.h"
43#endif
44
45#define DEFAULT_COMMAND_LINE "root=98:0"
46
47/* Changed in add_arg and setup_arch, which run before SMP is started */
48static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
49
50static void __init add_arg(char *arg)
51{
52	if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
53		printf("add_arg: Too many command line arguments!\n");
54		exit(1);
55	}
56	if(strlen(command_line) > 0)
57		strcat(command_line, " ");
58	strcat(command_line, arg);
59}
60
61struct cpuinfo_um boot_cpu_data = {
62	.loops_per_jiffy	= 0,
63	.ipi_pipe		= { -1, -1 }
64};
65
66unsigned long thread_saved_pc(struct task_struct *task)
67{
68	return os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
69					      task));
70}
71
72/* Changed in setup_arch, which is called in early boot */
73static char host_info[(__NEW_UTS_LEN + 1) * 5];
74
75static int show_cpuinfo(struct seq_file *m, void *v)
76{
77	int index = 0;
78
79#ifdef CONFIG_SMP
80	index = (struct cpuinfo_um *) v - cpu_data;
81	if (!cpu_online(index))
82		return 0;
83#endif
84
85	seq_printf(m, "processor\t: %d\n", index);
86	seq_printf(m, "vendor_id\t: User Mode Linux\n");
87	seq_printf(m, "model name\t: UML\n");
88	seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
89	seq_printf(m, "host\t\t: %s\n", host_info);
90	seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
91		   loops_per_jiffy/(500000/HZ),
92		   (loops_per_jiffy/(5000/HZ)) % 100);
93
94	return 0;
95}
96
97static void *c_start(struct seq_file *m, loff_t *pos)
98{
99	return *pos < NR_CPUS ? cpu_data + *pos : NULL;
100}
101
102static void *c_next(struct seq_file *m, void *v, loff_t *pos)
103{
104	++*pos;
105	return c_start(m, pos);
106}
107
108static void c_stop(struct seq_file *m, void *v)
109{
110}
111
112const struct seq_operations cpuinfo_op = {
113	.start	= c_start,
114	.next	= c_next,
115	.stop	= c_stop,
116	.show	= show_cpuinfo,
117};
118
119/* Set in linux_main */
120unsigned long host_task_size;
121unsigned long task_size;
122unsigned long uml_physmem;
123unsigned long uml_reserved; /* Also modified in mem_init */
124unsigned long start_vm;
125unsigned long end_vm;
126
127/* Set in uml_ncpus_setup */
128int ncpus = 1;
129
130#ifdef CONFIG_CMDLINE_ON_HOST
131/* Pointer set in linux_main, the array itself is private to each thread,
132 * and changed at address space creation time so this poses no concurrency
133 * problems.
134 */
135static char *argv1_begin = NULL;
136static char *argv1_end = NULL;
137#endif
138
139/* Set in early boot */
140static int have_root __initdata = 0;
141
142/* Set in uml_mem_setup and modified in linux_main */
143long long physmem_size = 32 * 1024 * 1024;
144
145void set_cmdline(char *cmd)
146{
147#ifdef CONFIG_CMDLINE_ON_HOST
148	char *umid, *ptr;
149
150	if(CHOOSE_MODE(honeypot, 0)) return;
151
152	umid = get_umid();
153	if(*umid != '\0'){
154		snprintf(argv1_begin,
155			 (argv1_end - argv1_begin) * sizeof(*ptr),
156			 "(%s) ", umid);
157		ptr = &argv1_begin[strlen(argv1_begin)];
158	}
159	else ptr = argv1_begin;
160
161	snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
162	memset(argv1_begin + strlen(argv1_begin), '\0',
163	       argv1_end - argv1_begin - strlen(argv1_begin));
164#endif
165}
166
167static char *usage_string =
168"User Mode Linux v%s\n"
169"	available at http://user-mode-linux.sourceforge.net/\n\n";
170
171static int __init uml_version_setup(char *line, int *add)
172{
173	printf("%s\n", init_utsname()->release);
174	exit(0);
175
176	return 0;
177}
178
179__uml_setup("--version", uml_version_setup,
180"--version\n"
181"    Prints the version number of the kernel.\n\n"
182);
183
184static int __init uml_root_setup(char *line, int *add)
185{
186	have_root = 1;
187	return 0;
188}
189
190__uml_setup("root=", uml_root_setup,
191"root=<file containing the root fs>\n"
192"    This is actually used by the generic kernel in exactly the same\n"
193"    way as in any other kernel. If you configure a number of block\n"
194"    devices and want to boot off something other than ubd0, you \n"
195"    would use something like:\n"
196"        root=/dev/ubd5\n\n"
197);
198
199#ifndef CONFIG_MODE_TT
200
201static int __init no_skas_debug_setup(char *line, int *add)
202{
203	printf("'debug' is not necessary to gdb UML in skas mode - run \n");
204	printf("'gdb linux' and disable CONFIG_CMDLINE_ON_HOST if gdb \n");
205	printf("doesn't work as expected\n");
206
207	return 0;
208}
209
210__uml_setup("debug", no_skas_debug_setup,
211"debug\n"
212"    this flag is not needed to run gdb on UML in skas mode\n\n"
213);
214
215#endif
216
217#ifdef CONFIG_SMP
218static int __init uml_ncpus_setup(char *line, int *add)
219{
220	if (!sscanf(line, "%d", &ncpus)) {
221		printf("Couldn't parse [%s]\n", line);
222		return -1;
223	}
224
225	return 0;
226}
227
228__uml_setup("ncpus=", uml_ncpus_setup,
229"ncpus=<# of desired CPUs>\n"
230"    This tells an SMP kernel how many virtual processors to start.\n\n"
231);
232#endif
233
234static int force_tt = 0;
235
236#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
237#define DEFAULT_TT 0
238
239static int __init mode_tt_setup(char *line, int *add)
240{
241	force_tt = 1;
242	return 0;
243}
244
245#else
246#ifdef CONFIG_MODE_SKAS
247
248#define DEFAULT_TT 0
249
250static int __init mode_tt_setup(char *line, int *add)
251{
252	printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
253	return 0;
254}
255
256#else
257#ifdef CONFIG_MODE_TT
258
259#define DEFAULT_TT 1
260
261static int __init mode_tt_setup(char *line, int *add)
262{
263	printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
264	return 0;
265}
266
267#endif
268#endif
269#endif
270
271__uml_setup("mode=tt", mode_tt_setup,
272"mode=tt\n"
273"    When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
274"    forces UML to run in tt (tracing thread) mode.  It is not the default\n"
275"    because it's slower and less secure than skas mode.\n\n"
276);
277
278int mode_tt = DEFAULT_TT;
279
280static int __init Usage(char *line, int *add)
281{
282	const char **p;
283
284	printf(usage_string, init_utsname()->release);
285	p = &__uml_help_start;
286	while (p < &__uml_help_end) {
287		printf("%s", *p);
288		p++;
289	}
290	exit(0);
291	return 0;
292}
293
294__uml_setup("--help", Usage,
295"--help\n"
296"    Prints this message.\n\n"
297);
298
299static int __init uml_checksetup(char *line, int *add)
300{
301	struct uml_param *p;
302
303	p = &__uml_setup_start;
304	while(p < &__uml_setup_end) {
305		int n;
306
307		n = strlen(p->str);
308		if(!strncmp(line, p->str, n)){
309			if (p->setup_func(line + n, add)) return 1;
310		}
311		p++;
312	}
313	return 0;
314}
315
316static void __init uml_postsetup(void)
317{
318	initcall_t *p;
319
320	p = &__uml_postsetup_start;
321	while(p < &__uml_postsetup_end){
322		(*p)();
323		p++;
324	}
325	return;
326}
327
328/* Set during early boot */
329unsigned long brk_start;
330unsigned long end_iomem;
331EXPORT_SYMBOL(end_iomem);
332
333#define MIN_VMALLOC (32 * 1024 * 1024)
334
335extern char __binary_start;
336
337int __init linux_main(int argc, char **argv)
338{
339	unsigned long avail, diff;
340	unsigned long virtmem_size, max_physmem;
341	unsigned int i, add;
342	char * mode;
343
344	for (i = 1; i < argc; i++){
345		if((i == 1) && (argv[i][0] == ' ')) continue;
346		add = 1;
347		uml_checksetup(argv[i], &add);
348		if (add)
349			add_arg(argv[i]);
350	}
351	if(have_root == 0)
352		add_arg(DEFAULT_COMMAND_LINE);
353
354	os_early_checks();
355	if (force_tt)
356		clear_can_do_skas();
357	mode_tt = force_tt ? 1 : !can_do_skas();
358#ifndef CONFIG_MODE_TT
359	if (mode_tt) {
360		/*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
361		 * can_do_skas() returned 0, and the message is correct. */
362		printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
363		exit(1);
364	}
365#endif
366
367#ifndef CONFIG_MODE_SKAS
368	mode = "TT";
369#else
370	/* Show to the user the result of selection */
371	if (mode_tt)
372		mode = "TT";
373	else if (proc_mm && ptrace_faultinfo)
374		mode = "SKAS3";
375	else
376		mode = "SKAS0";
377#endif
378
379	printf("UML running in %s mode\n", mode);
380
381	host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt,
382					  set_task_sizes_skas, &task_size);
383
384	/*
385	 * Setting up handlers to 'sig_info' struct
386	 */
387	os_fill_handlinfo(handlinfo_kern);
388
389	brk_start = (unsigned long) sbrk(0);
390	CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
391	/* Increase physical memory size for exec-shield users
392	so they actually get what they asked for. This should
393	add zero for non-exec shield users */
394
395	diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
396	if(diff > 1024 * 1024){
397		printf("Adding %ld bytes to physical memory to account for "
398		       "exec-shield gap\n", diff);
399		physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
400	}
401
402	uml_physmem = (unsigned long) &__binary_start & PAGE_MASK;
403
404	/* Reserve up to 4M after the current brk */
405	uml_reserved = ROUND_4M(brk_start) + (1 << 22);
406
407	setup_machinename(init_utsname()->machine);
408
409#ifdef CONFIG_CMDLINE_ON_HOST
410	argv1_begin = argv[1];
411	argv1_end = &argv[1][strlen(argv[1])];
412#endif
413
414	highmem = 0;
415	iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
416	max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
417
418	/* Zones have to begin on a 1 << MAX_ORDER page boundary,
419	 * so this makes sure that's true for highmem
420	 */
421	max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
422	if(physmem_size + iomem_size > max_physmem){
423		highmem = physmem_size + iomem_size - max_physmem;
424		physmem_size -= highmem;
425#ifndef CONFIG_HIGHMEM
426		highmem = 0;
427		printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
428		       "to %Lu bytes\n", physmem_size);
429#endif
430	}
431
432	high_physmem = uml_physmem + physmem_size;
433	end_iomem = high_physmem + iomem_size;
434	high_memory = (void *) end_iomem;
435
436	start_vm = VMALLOC_START;
437
438	setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
439	if(init_maps(physmem_size, iomem_size, highmem)){
440		printf("Failed to allocate mem_map for %Lu bytes of physical "
441		       "memory and %Lu bytes of highmem\n", physmem_size,
442		       highmem);
443		exit(1);
444	}
445
446	virtmem_size = physmem_size;
447	avail = get_kmem_end() - start_vm;
448	if(physmem_size > avail) virtmem_size = avail;
449	end_vm = start_vm + virtmem_size;
450
451	if(virtmem_size < physmem_size)
452		printf("Kernel virtual memory size shrunk to %lu bytes\n",
453		       virtmem_size);
454
455	uml_postsetup();
456
457	stack_protections((unsigned long) &init_thread_info);
458	os_flush_stdout();
459
460	return CHOOSE_MODE(start_uml_tt(), start_uml_skas());
461}
462
463extern int uml_exitcode;
464
465static int panic_exit(struct notifier_block *self, unsigned long unused1,
466		      void *unused2)
467{
468	bust_spinlocks(1);
469	show_regs(&(current->thread.regs));
470	bust_spinlocks(0);
471	uml_exitcode = 1;
472	os_dump_core();
473	return 0;
474}
475
476static struct notifier_block panic_exit_notifier = {
477	.notifier_call 		= panic_exit,
478	.next 			= NULL,
479	.priority 		= 0
480};
481
482void __init setup_arch(char **cmdline_p)
483{
484	atomic_notifier_chain_register(&panic_notifier_list,
485			&panic_exit_notifier);
486	paging_init();
487	strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
488	*cmdline_p = command_line;
489	setup_hostinfo(host_info, sizeof host_info);
490}
491
492void __init check_bugs(void)
493{
494	arch_check_bugs();
495	os_check_bugs();
496}
497
498void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
499{
500}
501
502#ifdef CONFIG_SMP
503void alternatives_smp_module_add(struct module *mod, char *name,
504				 void *locks, void *locks_end,
505				 void *text,  void *text_end)
506{
507}
508
509void alternatives_smp_module_del(struct module *mod)
510{
511}
512#endif
513