blob: 299d75a41a7f2f49320c389bf9b363c772dc36fa [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"
20#include "asm/page.h"
21#include "asm/pgtable.h"
22#include "asm/ptrace.h"
23#include "asm/elf.h"
24#include "asm/user.h"
Jeff Dike16c11162005-05-06 21:30:45 -070025#include "asm/setup.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include "ubd_user.h"
27#include "asm/current.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include "user_util.h"
29#include "kern_util.h"
30#include "kern.h"
31#include "mem_user.h"
32#include "mem.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include "initrd.h"
34#include "init.h"
35#include "os.h"
36#include "choose-mode.h"
37#include "mode_kern.h"
38#include "mode.h"
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -070039#ifdef UML_CONFIG_MODE_SKAS
40#include "skas.h"
41#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#define DEFAULT_COMMAND_LINE "root=98:0"
44
45/* Changed in linux_main and setup_arch, which run before SMP is started */
Alon Bar-Lev7a3a06d02007-02-12 00:54:26 -080046static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
Alon Bar-Lev7a3a06d02007-02-12 00:54:26 -080048static void __init add_arg(char *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070049{
50 if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
51 printf("add_arg: Too many command line arguments!\n");
52 exit(1);
53 }
54 if(strlen(command_line) > 0)
55 strcat(command_line, " ");
56 strcat(command_line, arg);
57}
58
59struct cpuinfo_um boot_cpu_data = {
60 .loops_per_jiffy = 0,
61 .ipi_pipe = { -1, -1 }
62};
63
64unsigned long thread_saved_pc(struct task_struct *task)
65{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070066 return os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
67 task));
Linus Torvalds1da177e2005-04-16 15:20:36 -070068}
69
70static int show_cpuinfo(struct seq_file *m, void *v)
71{
72 int index = 0;
73
74#ifdef CONFIG_SMP
75 index = (struct cpuinfo_um *) v - cpu_data;
76 if (!cpu_online(index))
77 return 0;
78#endif
79
80 seq_printf(m, "processor\t: %d\n", index);
81 seq_printf(m, "vendor_id\t: User Mode Linux\n");
82 seq_printf(m, "model name\t: UML\n");
83 seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
84 seq_printf(m, "host\t\t: %s\n", host_info);
85 seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
86 loops_per_jiffy/(500000/HZ),
87 (loops_per_jiffy/(5000/HZ)) % 100);
88
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070089 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090}
91
92static void *c_start(struct seq_file *m, loff_t *pos)
93{
94 return *pos < NR_CPUS ? cpu_data + *pos : NULL;
95}
96
97static void *c_next(struct seq_file *m, void *v, loff_t *pos)
98{
99 ++*pos;
100 return c_start(m, pos);
101}
102
103static void c_stop(struct seq_file *m, void *v)
104{
105}
106
Jeff Dike5e7672e2006-09-27 01:50:33 -0700107const struct seq_operations cpuinfo_op = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 .start = c_start,
109 .next = c_next,
110 .stop = c_stop,
111 .show = show_cpuinfo,
112};
113
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114/* Set in linux_main */
115unsigned long host_task_size;
116unsigned long task_size;
117
118unsigned long uml_start;
119
120/* Set in early boot */
121unsigned long uml_physmem;
122unsigned long uml_reserved;
123unsigned long start_vm;
124unsigned long end_vm;
125int ncpus = 1;
126
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700127#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128/* Pointer set in linux_main, the array itself is private to each thread,
129 * and changed at address space creation time so this poses no concurrency
130 * problems.
131 */
132static char *argv1_begin = NULL;
133static char *argv1_end = NULL;
134#endif
135
136/* Set in early boot */
137static int have_root __initdata = 0;
Jeff Dikeae173812005-11-07 00:58:57 -0800138long long physmem_size = 32 * 1024 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140void set_cmdline(char *cmd)
141{
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700142#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 char *umid, *ptr;
144
145 if(CHOOSE_MODE(honeypot, 0)) return;
146
Jeff Dike7eebe8a2006-01-06 00:19:01 -0800147 umid = get_umid();
148 if(*umid != '\0'){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 snprintf(argv1_begin,
150 (argv1_end - argv1_begin) * sizeof(*ptr),
151 "(%s) ", umid);
152 ptr = &argv1_begin[strlen(argv1_begin)];
153 }
154 else ptr = argv1_begin;
155
156 snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
157 memset(argv1_begin + strlen(argv1_begin), '\0',
158 argv1_end - argv1_begin - strlen(argv1_begin));
159#endif
160}
161
162static char *usage_string =
163"User Mode Linux v%s\n"
164" available at http://user-mode-linux.sourceforge.net/\n\n";
165
166static int __init uml_version_setup(char *line, int *add)
167{
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700168 printf("%s\n", init_utsname()->release);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 exit(0);
170
171 return 0;
172}
173
174__uml_setup("--version", uml_version_setup,
175"--version\n"
176" Prints the version number of the kernel.\n\n"
177);
178
179static int __init uml_root_setup(char *line, int *add)
180{
181 have_root = 1;
182 return 0;
183}
184
185__uml_setup("root=", uml_root_setup,
186"root=<file containing the root fs>\n"
187" This is actually used by the generic kernel in exactly the same\n"
188" way as in any other kernel. If you configure a number of block\n"
189" devices and want to boot off something other than ubd0, you \n"
190" would use something like:\n"
191" root=/dev/ubd5\n\n"
192);
193
Jeff Dikefbd55772006-02-07 12:58:40 -0800194#ifndef CONFIG_MODE_TT
195
196static int __init no_skas_debug_setup(char *line, int *add)
197{
198 printf("'debug' is not necessary to gdb UML in skas mode - run \n");
199 printf("'gdb linux' and disable CONFIG_CMDLINE_ON_HOST if gdb \n");
200 printf("doesn't work as expected\n");
201
202 return 0;
203}
204
205__uml_setup("debug", no_skas_debug_setup,
206"debug\n"
207" this flag is not needed to run gdb on UML in skas mode\n\n"
208);
209
210#endif
211
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212#ifdef CONFIG_SMP
213static int __init uml_ncpus_setup(char *line, int *add)
214{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700215 if (!sscanf(line, "%d", &ncpus)) {
216 printf("Couldn't parse [%s]\n", line);
217 return -1;
218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700220 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221}
222
223__uml_setup("ncpus=", uml_ncpus_setup,
224"ncpus=<# of desired CPUs>\n"
225" This tells an SMP kernel how many virtual processors to start.\n\n"
226);
227#endif
228
229static int force_tt = 0;
230
231#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
232#define DEFAULT_TT 0
233
234static int __init mode_tt_setup(char *line, int *add)
235{
236 force_tt = 1;
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700237 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238}
239
240#else
241#ifdef CONFIG_MODE_SKAS
242
243#define DEFAULT_TT 0
244
245static int __init mode_tt_setup(char *line, int *add)
246{
247 printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700248 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249}
250
251#else
252#ifdef CONFIG_MODE_TT
253
254#define DEFAULT_TT 1
255
256static int __init mode_tt_setup(char *line, int *add)
257{
258 printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700259 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260}
261
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262#endif
263#endif
264#endif
265
266__uml_setup("mode=tt", mode_tt_setup,
267"mode=tt\n"
268" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
269" forces UML to run in tt (tracing thread) mode. It is not the default\n"
270" because it's slower and less secure than skas mode.\n\n"
271);
272
273int mode_tt = DEFAULT_TT;
274
275static int __init Usage(char *line, int *add)
276{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700277 const char **p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700279 printf(usage_string, init_utsname()->release);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700280 p = &__uml_help_start;
281 while (p < &__uml_help_end) {
282 printf("%s", *p);
283 p++;
284 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 return 0;
287}
288
289__uml_setup("--help", Usage,
290"--help\n"
291" Prints this message.\n\n"
292);
293
294static int __init uml_checksetup(char *line, int *add)
295{
296 struct uml_param *p;
297
298 p = &__uml_setup_start;
299 while(p < &__uml_setup_end) {
300 int n;
301
302 n = strlen(p->str);
303 if(!strncmp(line, p->str, n)){
304 if (p->setup_func(line + n, add)) return 1;
305 }
306 p++;
307 }
308 return 0;
309}
310
311static void __init uml_postsetup(void)
312{
313 initcall_t *p;
314
315 p = &__uml_postsetup_start;
316 while(p < &__uml_postsetup_end){
317 (*p)();
318 p++;
319 }
320 return;
321}
322
323/* Set during early boot */
324unsigned long brk_start;
325unsigned long end_iomem;
326EXPORT_SYMBOL(end_iomem);
327
328#define MIN_VMALLOC (32 * 1024 * 1024)
329
Jeff Dike23bbd582006-07-10 04:45:06 -0700330extern char __binary_start;
331
Alon Bar-Lev7a3a06d02007-02-12 00:54:26 -0800332int __init linux_main(int argc, char **argv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
334 unsigned long avail, diff;
335 unsigned long virtmem_size, max_physmem;
336 unsigned int i, add;
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700337 char * mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
339 for (i = 1; i < argc; i++){
340 if((i == 1) && (argv[i][0] == ' ')) continue;
341 add = 1;
342 uml_checksetup(argv[i], &add);
343 if (add)
344 add_arg(argv[i]);
345 }
346 if(have_root == 0)
347 add_arg(DEFAULT_COMMAND_LINE);
348
Gennady Sharapov60d339f2005-09-03 15:57:47 -0700349 os_early_checks();
Paolo 'Blaisorblade' Giarrusso89236482005-09-30 11:59:00 -0700350 if (force_tt)
351 clear_can_do_skas();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 mode_tt = force_tt ? 1 : !can_do_skas();
353#ifndef CONFIG_MODE_TT
354 if (mode_tt) {
355 /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
356 * can_do_skas() returned 0, and the message is correct. */
357 printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
358 exit(1);
359 }
360#endif
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700361
362#ifndef CONFIG_MODE_SKAS
363 mode = "TT";
364#else
365 /* Show to the user the result of selection */
366 if (mode_tt)
367 mode = "TT";
368 else if (proc_mm && ptrace_faultinfo)
369 mode = "SKAS3";
370 else
371 mode = "SKAS0";
372#endif
373
374 printf("UML running in %s mode\n", mode);
375
Jeff Dike23bbd582006-07-10 04:45:06 -0700376 uml_start = (unsigned long) &__binary_start;
377 host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt,
378 set_task_sizes_skas, &task_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800380 /*
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700381 * Setting up handlers to 'sig_info' struct
382 */
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800383 os_fill_handlinfo(handlinfo_kern);
384
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 brk_start = (unsigned long) sbrk(0);
386 CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
387 /* Increase physical memory size for exec-shield users
388 so they actually get what they asked for. This should
389 add zero for non-exec shield users */
390
391 diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
392 if(diff > 1024 * 1024){
393 printf("Adding %ld bytes to physical memory to account for "
394 "exec-shield gap\n", diff);
395 physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
396 }
397
Jeff Dike23bbd582006-07-10 04:45:06 -0700398 uml_physmem = uml_start & PAGE_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
400 /* Reserve up to 4M after the current brk */
401 uml_reserved = ROUND_4M(brk_start) + (1 << 22);
402
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700403 setup_machinename(init_utsname()->machine);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700405#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 argv1_begin = argv[1];
407 argv1_end = &argv[1][strlen(argv[1])];
408#endif
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 highmem = 0;
411 iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
412 max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
413
414 /* Zones have to begin on a 1 << MAX_ORDER page boundary,
415 * so this makes sure that's true for highmem
416 */
417 max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
418 if(physmem_size + iomem_size > max_physmem){
419 highmem = physmem_size + iomem_size - max_physmem;
420 physmem_size -= highmem;
421#ifndef CONFIG_HIGHMEM
422 highmem = 0;
423 printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
Jeff Diked9f8b622006-03-27 01:14:29 -0800424 "to %Lu bytes\n", physmem_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425#endif
426 }
427
428 high_physmem = uml_physmem + physmem_size;
429 end_iomem = high_physmem + iomem_size;
430 high_memory = (void *) end_iomem;
431
432 start_vm = VMALLOC_START;
433
434 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
435 if(init_maps(physmem_size, iomem_size, highmem)){
Jeff Diked9f8b622006-03-27 01:14:29 -0800436 printf("Failed to allocate mem_map for %Lu bytes of physical "
437 "memory and %Lu bytes of highmem\n", physmem_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 highmem);
439 exit(1);
440 }
441
442 virtmem_size = physmem_size;
443 avail = get_kmem_end() - start_vm;
444 if(physmem_size > avail) virtmem_size = avail;
445 end_vm = start_vm + virtmem_size;
446
447 if(virtmem_size < physmem_size)
Jeff Dikeae173812005-11-07 00:58:57 -0800448 printf("Kernel virtual memory size shrunk to %lu bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 virtmem_size);
450
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700451 uml_postsetup();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
453 task_protections((unsigned long) &init_thread_info);
454 os_flush_stdout();
455
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700456 return CHOOSE_MODE(start_uml_tt(), start_uml_skas());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457}
458
459extern int uml_exitcode;
460
461static int panic_exit(struct notifier_block *self, unsigned long unused1,
462 void *unused2)
463{
464 bust_spinlocks(1);
465 show_regs(&(current->thread.regs));
466 bust_spinlocks(0);
467 uml_exitcode = 1;
468 machine_halt();
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700469 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470}
471
472static struct notifier_block panic_exit_notifier = {
473 .notifier_call = panic_exit,
474 .next = NULL,
475 .priority = 0
476};
477
478void __init setup_arch(char **cmdline_p)
479{
Alan Sterne041c682006-03-27 01:16:30 -0800480 atomic_notifier_chain_register(&panic_notifier_list,
481 &panic_exit_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 paging_init();
Alon Bar-Lev19bf7e72007-02-12 00:54:23 -0800483 strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700484 *cmdline_p = command_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 setup_hostinfo();
486}
487
488void __init check_bugs(void)
489{
490 arch_check_bugs();
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700491 os_check_bugs();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492}
493
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800494void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
495{
496}
497
Theodore Tsoc61a8412006-07-03 00:24:09 -0700498#ifdef CONFIG_SMP
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800499void alternatives_smp_module_add(struct module *mod, char *name,
500 void *locks, void *locks_end,
501 void *text, void *text_end)
502{
503}
504
505void alternatives_smp_module_del(struct module *mod)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506{
507}
Theodore Tsoc61a8412006-07-03 00:24:09 -0700508#endif