blob: 73747ac197748d6deb1649f0b59b4b1aad1d7051 [file] [log] [blame]
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -08001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/config.h"
7#include "linux/kernel.h"
8#include "linux/sched.h"
9#include "linux/notifier.h"
10#include "linux/mm.h"
11#include "linux/types.h"
12#include "linux/tty.h"
13#include "linux/init.h"
14#include "linux/bootmem.h"
15#include "linux/spinlock.h"
16#include "linux/utsname.h"
17#include "linux/sysrq.h"
18#include "linux/seq_file.h"
19#include "linux/delay.h"
20#include "linux/module.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"
Jeff Dike16c11162005-05-06 21:30:45 -070026#include "asm/setup.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include "ubd_user.h"
28#include "asm/current.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include "user_util.h"
30#include "kern_util.h"
31#include "kern.h"
32#include "mem_user.h"
33#include "mem.h"
34#include "umid.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"
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -070041#ifdef UML_CONFIG_MODE_SKAS
42#include "skas.h"
43#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45#define DEFAULT_COMMAND_LINE "root=98:0"
46
47/* Changed in linux_main and setup_arch, which run before SMP is started */
Jeff Dike16c11162005-05-06 21:30:45 -070048static char command_line[COMMAND_LINE_SIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Jeff Dike16c11162005-05-06 21:30:45 -070050static void add_arg(char *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070051{
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
72static int show_cpuinfo(struct seq_file *m, void *v)
73{
74 int index = 0;
75
76#ifdef CONFIG_SMP
77 index = (struct cpuinfo_um *) v - cpu_data;
78 if (!cpu_online(index))
79 return 0;
80#endif
81
82 seq_printf(m, "processor\t: %d\n", index);
83 seq_printf(m, "vendor_id\t: User Mode Linux\n");
84 seq_printf(m, "model name\t: UML\n");
85 seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
86 seq_printf(m, "host\t\t: %s\n", host_info);
87 seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
88 loops_per_jiffy/(500000/HZ),
89 (loops_per_jiffy/(5000/HZ)) % 100);
90
91 return(0);
92}
93
94static void *c_start(struct seq_file *m, loff_t *pos)
95{
96 return *pos < NR_CPUS ? cpu_data + *pos : NULL;
97}
98
99static void *c_next(struct seq_file *m, void *v, loff_t *pos)
100{
101 ++*pos;
102 return c_start(m, pos);
103}
104
105static void c_stop(struct seq_file *m, void *v)
106{
107}
108
109struct seq_operations cpuinfo_op = {
110 .start = c_start,
111 .next = c_next,
112 .stop = c_stop,
113 .show = show_cpuinfo,
114};
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116/* Set in linux_main */
117unsigned long host_task_size;
118unsigned long task_size;
119
120unsigned long uml_start;
121
122/* Set in early boot */
123unsigned long uml_physmem;
124unsigned long uml_reserved;
125unsigned long start_vm;
126unsigned long end_vm;
127int ncpus = 1;
128
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700129#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130/* Pointer set in linux_main, the array itself is private to each thread,
131 * and changed at address space creation time so this poses no concurrency
132 * problems.
133 */
134static char *argv1_begin = NULL;
135static char *argv1_end = NULL;
136#endif
137
138/* Set in early boot */
139static int have_root __initdata = 0;
Jeff Dikeae173812005-11-07 00:58:57 -0800140long long physmem_size = 32 * 1024 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142void set_cmdline(char *cmd)
143{
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700144#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 char *umid, *ptr;
146
147 if(CHOOSE_MODE(honeypot, 0)) return;
148
Jeff Dike7eebe8a2006-01-06 00:19:01 -0800149 umid = get_umid();
150 if(*umid != '\0'){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 snprintf(argv1_begin,
152 (argv1_end - argv1_begin) * sizeof(*ptr),
153 "(%s) ", umid);
154 ptr = &argv1_begin[strlen(argv1_begin)];
155 }
156 else ptr = argv1_begin;
157
158 snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
159 memset(argv1_begin + strlen(argv1_begin), '\0',
160 argv1_end - argv1_begin - strlen(argv1_begin));
161#endif
162}
163
164static char *usage_string =
165"User Mode Linux v%s\n"
166" available at http://user-mode-linux.sourceforge.net/\n\n";
167
168static int __init uml_version_setup(char *line, int *add)
169{
170 printf("%s\n", system_utsname.release);
171 exit(0);
172
173 return 0;
174}
175
176__uml_setup("--version", uml_version_setup,
177"--version\n"
178" Prints the version number of the kernel.\n\n"
179);
180
181static int __init uml_root_setup(char *line, int *add)
182{
183 have_root = 1;
184 return 0;
185}
186
187__uml_setup("root=", uml_root_setup,
188"root=<file containing the root fs>\n"
189" This is actually used by the generic kernel in exactly the same\n"
190" way as in any other kernel. If you configure a number of block\n"
191" devices and want to boot off something other than ubd0, you \n"
192" would use something like:\n"
193" root=/dev/ubd5\n\n"
194);
195
196#ifdef CONFIG_SMP
197static int __init uml_ncpus_setup(char *line, int *add)
198{
199 if (!sscanf(line, "%d", &ncpus)) {
200 printf("Couldn't parse [%s]\n", line);
201 return -1;
202 }
203
204 return 0;
205}
206
207__uml_setup("ncpus=", uml_ncpus_setup,
208"ncpus=<# of desired CPUs>\n"
209" This tells an SMP kernel how many virtual processors to start.\n\n"
210);
211#endif
212
213static int force_tt = 0;
214
215#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
216#define DEFAULT_TT 0
217
218static int __init mode_tt_setup(char *line, int *add)
219{
220 force_tt = 1;
221 return(0);
222}
223
224#else
225#ifdef CONFIG_MODE_SKAS
226
227#define DEFAULT_TT 0
228
229static int __init mode_tt_setup(char *line, int *add)
230{
231 printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
232 return(0);
233}
234
235#else
236#ifdef CONFIG_MODE_TT
237
238#define DEFAULT_TT 1
239
240static int __init mode_tt_setup(char *line, int *add)
241{
242 printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
243 return(0);
244}
245
246#else
247
248#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled
249
250#endif
251#endif
252#endif
253
254__uml_setup("mode=tt", mode_tt_setup,
255"mode=tt\n"
256" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
257" forces UML to run in tt (tracing thread) mode. It is not the default\n"
258" because it's slower and less secure than skas mode.\n\n"
259);
260
261int mode_tt = DEFAULT_TT;
262
263static int __init Usage(char *line, int *add)
264{
265 const char **p;
266
267 printf(usage_string, system_utsname.release);
268 p = &__uml_help_start;
269 while (p < &__uml_help_end) {
270 printf("%s", *p);
271 p++;
272 }
273 exit(0);
274
275 return 0;
276}
277
278__uml_setup("--help", Usage,
279"--help\n"
280" Prints this message.\n\n"
281);
282
283static int __init uml_checksetup(char *line, int *add)
284{
285 struct uml_param *p;
286
287 p = &__uml_setup_start;
288 while(p < &__uml_setup_end) {
289 int n;
290
291 n = strlen(p->str);
292 if(!strncmp(line, p->str, n)){
293 if (p->setup_func(line + n, add)) return 1;
294 }
295 p++;
296 }
297 return 0;
298}
299
300static void __init uml_postsetup(void)
301{
302 initcall_t *p;
303
304 p = &__uml_postsetup_start;
305 while(p < &__uml_postsetup_end){
306 (*p)();
307 p++;
308 }
309 return;
310}
311
312/* Set during early boot */
313unsigned long brk_start;
314unsigned long end_iomem;
315EXPORT_SYMBOL(end_iomem);
316
317#define MIN_VMALLOC (32 * 1024 * 1024)
318
319int linux_main(int argc, char **argv)
320{
321 unsigned long avail, diff;
322 unsigned long virtmem_size, max_physmem;
323 unsigned int i, add;
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700324 char * mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 for (i = 1; i < argc; i++){
327 if((i == 1) && (argv[i][0] == ' ')) continue;
328 add = 1;
329 uml_checksetup(argv[i], &add);
330 if (add)
331 add_arg(argv[i]);
332 }
333 if(have_root == 0)
334 add_arg(DEFAULT_COMMAND_LINE);
335
Gennady Sharapov60d339f2005-09-03 15:57:47 -0700336 os_early_checks();
Paolo 'Blaisorblade' Giarrusso89236482005-09-30 11:59:00 -0700337 if (force_tt)
338 clear_can_do_skas();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 mode_tt = force_tt ? 1 : !can_do_skas();
340#ifndef CONFIG_MODE_TT
341 if (mode_tt) {
342 /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
343 * can_do_skas() returned 0, and the message is correct. */
344 printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
345 exit(1);
346 }
347#endif
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700348
349#ifndef CONFIG_MODE_SKAS
350 mode = "TT";
351#else
352 /* Show to the user the result of selection */
353 if (mode_tt)
354 mode = "TT";
355 else if (proc_mm && ptrace_faultinfo)
356 mode = "SKAS3";
357 else
358 mode = "SKAS0";
359#endif
360
361 printf("UML running in %s mode\n", mode);
362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
364 &host_task_size, &task_size);
365
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800366 /*
367 * Setting up handlers to 'sig_info' struct
368 */
369 os_fill_handlinfo(handlinfo_kern);
370
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 brk_start = (unsigned long) sbrk(0);
372 CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
373 /* Increase physical memory size for exec-shield users
374 so they actually get what they asked for. This should
375 add zero for non-exec shield users */
376
377 diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
378 if(diff > 1024 * 1024){
379 printf("Adding %ld bytes to physical memory to account for "
380 "exec-shield gap\n", diff);
381 physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
382 }
383
384 uml_physmem = uml_start;
385
386 /* Reserve up to 4M after the current brk */
387 uml_reserved = ROUND_4M(brk_start) + (1 << 22);
388
389 setup_machinename(system_utsname.machine);
390
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700391#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 argv1_begin = argv[1];
393 argv1_end = &argv[1][strlen(argv[1])];
394#endif
395
396 highmem = 0;
397 iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
398 max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
399
400 /* Zones have to begin on a 1 << MAX_ORDER page boundary,
401 * so this makes sure that's true for highmem
402 */
403 max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
404 if(physmem_size + iomem_size > max_physmem){
405 highmem = physmem_size + iomem_size - max_physmem;
406 physmem_size -= highmem;
407#ifndef CONFIG_HIGHMEM
408 highmem = 0;
409 printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
Jeff Dikeae173812005-11-07 00:58:57 -0800410 "to %lu bytes\n", physmem_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411#endif
412 }
413
414 high_physmem = uml_physmem + physmem_size;
415 end_iomem = high_physmem + iomem_size;
416 high_memory = (void *) end_iomem;
417
418 start_vm = VMALLOC_START;
419
420 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
421 if(init_maps(physmem_size, iomem_size, highmem)){
Jeff Dikeae173812005-11-07 00:58:57 -0800422 printf("Failed to allocate mem_map for %lu bytes of physical "
423 "memory and %lu bytes of highmem\n", physmem_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 highmem);
425 exit(1);
426 }
427
428 virtmem_size = physmem_size;
429 avail = get_kmem_end() - start_vm;
430 if(physmem_size > avail) virtmem_size = avail;
431 end_vm = start_vm + virtmem_size;
432
433 if(virtmem_size < physmem_size)
Jeff Dikeae173812005-11-07 00:58:57 -0800434 printf("Kernel virtual memory size shrunk to %lu bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 virtmem_size);
436
437 uml_postsetup();
438
439 task_protections((unsigned long) &init_thread_info);
440 os_flush_stdout();
441
442 return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
443}
444
445extern int uml_exitcode;
446
447static int panic_exit(struct notifier_block *self, unsigned long unused1,
448 void *unused2)
449{
450 bust_spinlocks(1);
451 show_regs(&(current->thread.regs));
452 bust_spinlocks(0);
453 uml_exitcode = 1;
454 machine_halt();
455 return(0);
456}
457
458static struct notifier_block panic_exit_notifier = {
459 .notifier_call = panic_exit,
460 .next = NULL,
461 .priority = 0
462};
463
464void __init setup_arch(char **cmdline_p)
465{
466 notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
467 paging_init();
Jeff Dike16c11162005-05-06 21:30:45 -0700468 strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 *cmdline_p = command_line;
470 setup_hostinfo();
471}
472
473void __init check_bugs(void)
474{
475 arch_check_bugs();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 check_sigio();
477 check_devanon();
478}
479
480void apply_alternatives(void *start, void *end)
481{
482}