blob: 613fb082bbd5896ed8a14d391ff4243ae1f17362 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -07006#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"
Jeff Dikeb4ffb6a2007-05-06 14:50:59 -070020#include "linux/utsname.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#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"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include "initrd.h"
35#include "init.h"
36#include "os.h"
37#include "choose-mode.h"
38#include "mode_kern.h"
39#include "mode.h"
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -070040#ifdef UML_CONFIG_MODE_SKAS
41#include "skas.h"
42#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44#define DEFAULT_COMMAND_LINE "root=98:0"
45
46/* Changed in linux_main and setup_arch, which run before SMP is started */
Alon Bar-Lev7a3a06d02007-02-12 00:54:26 -080047static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
Alon Bar-Lev7a3a06d02007-02-12 00:54:26 -080049static void __init add_arg(char *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050{
51 if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
52 printf("add_arg: Too many command line arguments!\n");
53 exit(1);
54 }
55 if(strlen(command_line) > 0)
56 strcat(command_line, " ");
57 strcat(command_line, arg);
58}
59
60struct cpuinfo_um boot_cpu_data = {
61 .loops_per_jiffy = 0,
62 .ipi_pipe = { -1, -1 }
63};
64
65unsigned long thread_saved_pc(struct task_struct *task)
66{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070067 return os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
68 task));
Linus Torvalds1da177e2005-04-16 15:20:36 -070069}
70
Jeff Dikeb4ffb6a2007-05-06 14:50:59 -070071/* Changed in setup_arch, which is called in early boot */
72static char host_info[(__NEW_UTS_LEN + 1) * 5];
73
Linus Torvalds1da177e2005-04-16 15:20:36 -070074static int show_cpuinfo(struct seq_file *m, void *v)
75{
76 int index = 0;
77
78#ifdef CONFIG_SMP
79 index = (struct cpuinfo_um *) v - cpu_data;
80 if (!cpu_online(index))
81 return 0;
82#endif
83
84 seq_printf(m, "processor\t: %d\n", index);
85 seq_printf(m, "vendor_id\t: User Mode Linux\n");
86 seq_printf(m, "model name\t: UML\n");
87 seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
88 seq_printf(m, "host\t\t: %s\n", host_info);
89 seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
90 loops_per_jiffy/(500000/HZ),
91 (loops_per_jiffy/(5000/HZ)) % 100);
92
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070093 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094}
95
96static void *c_start(struct seq_file *m, loff_t *pos)
97{
98 return *pos < NR_CPUS ? cpu_data + *pos : NULL;
99}
100
101static void *c_next(struct seq_file *m, void *v, loff_t *pos)
102{
103 ++*pos;
104 return c_start(m, pos);
105}
106
107static void c_stop(struct seq_file *m, void *v)
108{
109}
110
Jeff Dike5e7672e2006-09-27 01:50:33 -0700111const struct seq_operations cpuinfo_op = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 .start = c_start,
113 .next = c_next,
114 .stop = c_stop,
115 .show = show_cpuinfo,
116};
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118/* Set in linux_main */
119unsigned long host_task_size;
120unsigned long task_size;
121
122unsigned long uml_start;
123
124/* Set in early boot */
125unsigned long uml_physmem;
126unsigned long uml_reserved;
127unsigned long start_vm;
128unsigned long end_vm;
129int ncpus = 1;
130
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700131#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132/* Pointer set in linux_main, the array itself is private to each thread,
133 * and changed at address space creation time so this poses no concurrency
134 * problems.
135 */
136static char *argv1_begin = NULL;
137static char *argv1_end = NULL;
138#endif
139
140/* Set in early boot */
141static int have_root __initdata = 0;
Jeff Dikeae173812005-11-07 00:58:57 -0800142long long physmem_size = 32 * 1024 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144void set_cmdline(char *cmd)
145{
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700146#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 char *umid, *ptr;
148
149 if(CHOOSE_MODE(honeypot, 0)) return;
150
Jeff Dike7eebe8a2006-01-06 00:19:01 -0800151 umid = get_umid();
152 if(*umid != '\0'){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 snprintf(argv1_begin,
154 (argv1_end - argv1_begin) * sizeof(*ptr),
155 "(%s) ", umid);
156 ptr = &argv1_begin[strlen(argv1_begin)];
157 }
158 else ptr = argv1_begin;
159
160 snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
161 memset(argv1_begin + strlen(argv1_begin), '\0',
162 argv1_end - argv1_begin - strlen(argv1_begin));
163#endif
164}
165
166static char *usage_string =
167"User Mode Linux v%s\n"
168" available at http://user-mode-linux.sourceforge.net/\n\n";
169
170static int __init uml_version_setup(char *line, int *add)
171{
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700172 printf("%s\n", init_utsname()->release);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 exit(0);
174
175 return 0;
176}
177
178__uml_setup("--version", uml_version_setup,
179"--version\n"
180" Prints the version number of the kernel.\n\n"
181);
182
183static int __init uml_root_setup(char *line, int *add)
184{
185 have_root = 1;
186 return 0;
187}
188
189__uml_setup("root=", uml_root_setup,
190"root=<file containing the root fs>\n"
191" This is actually used by the generic kernel in exactly the same\n"
192" way as in any other kernel. If you configure a number of block\n"
193" devices and want to boot off something other than ubd0, you \n"
194" would use something like:\n"
195" root=/dev/ubd5\n\n"
196);
197
Jeff Dikefbd55772006-02-07 12:58:40 -0800198#ifndef CONFIG_MODE_TT
199
200static int __init no_skas_debug_setup(char *line, int *add)
201{
202 printf("'debug' is not necessary to gdb UML in skas mode - run \n");
203 printf("'gdb linux' and disable CONFIG_CMDLINE_ON_HOST if gdb \n");
204 printf("doesn't work as expected\n");
205
206 return 0;
207}
208
209__uml_setup("debug", no_skas_debug_setup,
210"debug\n"
211" this flag is not needed to run gdb on UML in skas mode\n\n"
212);
213
214#endif
215
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216#ifdef CONFIG_SMP
217static int __init uml_ncpus_setup(char *line, int *add)
218{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700219 if (!sscanf(line, "%d", &ncpus)) {
220 printf("Couldn't parse [%s]\n", line);
221 return -1;
222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700224 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225}
226
227__uml_setup("ncpus=", uml_ncpus_setup,
228"ncpus=<# of desired CPUs>\n"
229" This tells an SMP kernel how many virtual processors to start.\n\n"
230);
231#endif
232
233static int force_tt = 0;
234
235#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
236#define DEFAULT_TT 0
237
238static int __init mode_tt_setup(char *line, int *add)
239{
240 force_tt = 1;
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700241 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242}
243
244#else
245#ifdef CONFIG_MODE_SKAS
246
247#define DEFAULT_TT 0
248
249static int __init mode_tt_setup(char *line, int *add)
250{
251 printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700252 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253}
254
255#else
256#ifdef CONFIG_MODE_TT
257
258#define DEFAULT_TT 1
259
260static int __init mode_tt_setup(char *line, int *add)
261{
262 printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700263 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264}
265
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266#endif
267#endif
268#endif
269
270__uml_setup("mode=tt", mode_tt_setup,
271"mode=tt\n"
272" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
273" forces UML to run in tt (tracing thread) mode. It is not the default\n"
274" because it's slower and less secure than skas mode.\n\n"
275);
276
277int mode_tt = DEFAULT_TT;
278
279static int __init Usage(char *line, int *add)
280{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700281 const char **p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700283 printf(usage_string, init_utsname()->release);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700284 p = &__uml_help_start;
285 while (p < &__uml_help_end) {
286 printf("%s", *p);
287 p++;
288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 return 0;
291}
292
293__uml_setup("--help", Usage,
294"--help\n"
295" Prints this message.\n\n"
296);
297
298static int __init uml_checksetup(char *line, int *add)
299{
300 struct uml_param *p;
301
302 p = &__uml_setup_start;
303 while(p < &__uml_setup_end) {
304 int n;
305
306 n = strlen(p->str);
307 if(!strncmp(line, p->str, n)){
308 if (p->setup_func(line + n, add)) return 1;
309 }
310 p++;
311 }
312 return 0;
313}
314
315static void __init uml_postsetup(void)
316{
317 initcall_t *p;
318
319 p = &__uml_postsetup_start;
320 while(p < &__uml_postsetup_end){
321 (*p)();
322 p++;
323 }
324 return;
325}
326
327/* Set during early boot */
328unsigned long brk_start;
329unsigned long end_iomem;
330EXPORT_SYMBOL(end_iomem);
331
332#define MIN_VMALLOC (32 * 1024 * 1024)
333
Jeff Dike23bbd582006-07-10 04:45:06 -0700334extern char __binary_start;
335
Alon Bar-Lev7a3a06d02007-02-12 00:54:26 -0800336int __init linux_main(int argc, char **argv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
338 unsigned long avail, diff;
339 unsigned long virtmem_size, max_physmem;
340 unsigned int i, add;
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700341 char * mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 for (i = 1; i < argc; i++){
344 if((i == 1) && (argv[i][0] == ' ')) continue;
345 add = 1;
346 uml_checksetup(argv[i], &add);
347 if (add)
348 add_arg(argv[i]);
349 }
350 if(have_root == 0)
351 add_arg(DEFAULT_COMMAND_LINE);
352
Gennady Sharapov60d339f62005-09-03 15:57:47 -0700353 os_early_checks();
Paolo 'Blaisorblade' Giarrusso89236482005-09-30 11:59:00 -0700354 if (force_tt)
355 clear_can_do_skas();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 mode_tt = force_tt ? 1 : !can_do_skas();
357#ifndef CONFIG_MODE_TT
358 if (mode_tt) {
359 /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
360 * can_do_skas() returned 0, and the message is correct. */
361 printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
362 exit(1);
363 }
364#endif
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700365
366#ifndef CONFIG_MODE_SKAS
367 mode = "TT";
368#else
369 /* Show to the user the result of selection */
370 if (mode_tt)
371 mode = "TT";
372 else if (proc_mm && ptrace_faultinfo)
373 mode = "SKAS3";
374 else
375 mode = "SKAS0";
376#endif
377
378 printf("UML running in %s mode\n", mode);
379
Jeff Dike23bbd582006-07-10 04:45:06 -0700380 uml_start = (unsigned long) &__binary_start;
381 host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt,
382 set_task_sizes_skas, &task_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800384 /*
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700385 * Setting up handlers to 'sig_info' struct
386 */
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800387 os_fill_handlinfo(handlinfo_kern);
388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 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
Jeff Dike23bbd582006-07-10 04:45:06 -0700402 uml_physmem = uml_start & PAGE_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
404 /* Reserve up to 4M after the current brk */
405 uml_reserved = ROUND_4M(brk_start) + (1 << 22);
406
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700407 setup_machinename(init_utsname()->machine);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700409#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 argv1_begin = argv[1];
411 argv1_end = &argv[1][strlen(argv[1])];
412#endif
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700413
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 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 "
Jeff Diked9f8b622006-03-27 01:14:29 -0800428 "to %Lu bytes\n", physmem_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429#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)){
Jeff Diked9f8b622006-03-27 01:14:29 -0800440 printf("Failed to allocate mem_map for %Lu bytes of physical "
441 "memory and %Lu bytes of highmem\n", physmem_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 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)
Jeff Dikeae173812005-11-07 00:58:57 -0800452 printf("Kernel virtual memory size shrunk to %lu bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 virtmem_size);
454
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700455 uml_postsetup();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
457 task_protections((unsigned long) &init_thread_info);
458 os_flush_stdout();
459
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700460 return CHOOSE_MODE(start_uml_tt(), start_uml_skas());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461}
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 machine_halt();
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700473 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474}
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{
Alan Sterne041c682006-03-27 01:16:30 -0800484 atomic_notifier_chain_register(&panic_notifier_list,
485 &panic_exit_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 paging_init();
Alon Bar-Lev19bf7e72007-02-12 00:54:23 -0800487 strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700488 *cmdline_p = command_line;
Jeff Dikeb4ffb6a2007-05-06 14:50:59 -0700489 setup_hostinfo(host_info, sizeof host_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490}
491
492void __init check_bugs(void)
493{
494 arch_check_bugs();
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700495 os_check_bugs();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496}
497
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800498void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
499{
500}
501
Theodore Tsoc61a84162006-07-03 00:24:09 -0700502#ifdef CONFIG_SMP
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800503void 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)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
511}
Theodore Tsoc61a84162006-07-03 00:24:09 -0700512#endif