blob: 8eefb5202c501bb34f67bf060f638538e9b6c00a [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"
Jeff Dikeeb830752007-05-06 14:51:07 -070031#include "arch.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "kern.h"
33#include "mem_user.h"
34#include "mem.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#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 */
Alon Bar-Lev7a3a06d02007-02-12 00:54:26 -080048static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Alon Bar-Lev7a3a06d02007-02-12 00:54:26 -080050static void __init 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{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070068 return os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
69 task));
Linus Torvalds1da177e2005-04-16 15:20:36 -070070}
71
Jeff Dikeb4ffb6a2007-05-06 14:50:59 -070072/* Changed in setup_arch, which is called in early boot */
73static char host_info[(__NEW_UTS_LEN + 1) * 5];
74
Linus Torvalds1da177e2005-04-16 15:20:36 -070075static 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
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070094 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095}
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
Jeff Dike5e7672e2006-09-27 01:50:33 -0700112const struct seq_operations cpuinfo_op = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 .start = c_start,
114 .next = c_next,
115 .stop = c_stop,
116 .show = show_cpuinfo,
117};
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119/* Set in linux_main */
120unsigned long host_task_size;
121unsigned long task_size;
122
123unsigned long uml_start;
124
125/* Set in early boot */
126unsigned long uml_physmem;
127unsigned long uml_reserved;
128unsigned long start_vm;
129unsigned long end_vm;
130int ncpus = 1;
131
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700132#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133/* Pointer set in linux_main, the array itself is private to each thread,
134 * and changed at address space creation time so this poses no concurrency
135 * problems.
136 */
137static char *argv1_begin = NULL;
138static char *argv1_end = NULL;
139#endif
140
141/* Set in early boot */
142static int have_root __initdata = 0;
Jeff Dikeae173812005-11-07 00:58:57 -0800143long long physmem_size = 32 * 1024 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145void set_cmdline(char *cmd)
146{
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700147#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 char *umid, *ptr;
149
150 if(CHOOSE_MODE(honeypot, 0)) return;
151
Jeff Dike7eebe8a2006-01-06 00:19:01 -0800152 umid = get_umid();
153 if(*umid != '\0'){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 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{
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700173 printf("%s\n", init_utsname()->release);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 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
Jeff Dikefbd55772006-02-07 12:58:40 -0800199#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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217#ifdef CONFIG_SMP
218static int __init uml_ncpus_setup(char *line, int *add)
219{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700220 if (!sscanf(line, "%d", &ncpus)) {
221 printf("Couldn't parse [%s]\n", line);
222 return -1;
223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700225 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226}
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;
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700242 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243}
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");
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700253 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254}
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");
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700264 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265}
266
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267#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{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700282 const char **p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700284 printf(usage_string, init_utsname()->release);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700285 p = &__uml_help_start;
286 while (p < &__uml_help_end) {
287 printf("%s", *p);
288 p++;
289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 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
Jeff Dike23bbd582006-07-10 04:45:06 -0700335extern char __binary_start;
336
Alon Bar-Lev7a3a06d02007-02-12 00:54:26 -0800337int __init linux_main(int argc, char **argv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
339 unsigned long avail, diff;
340 unsigned long virtmem_size, max_physmem;
341 unsigned int i, add;
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700342 char * mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
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
Gennady Sharapov60d339f2005-09-03 15:57:47 -0700354 os_early_checks();
Paolo 'Blaisorblade' Giarrusso89236482005-09-30 11:59:00 -0700355 if (force_tt)
356 clear_can_do_skas();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 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
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700366
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
Jeff Dike23bbd582006-07-10 04:45:06 -0700381 uml_start = (unsigned long) &__binary_start;
382 host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt,
383 set_task_sizes_skas, &task_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800385 /*
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700386 * Setting up handlers to 'sig_info' struct
387 */
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800388 os_fill_handlinfo(handlinfo_kern);
389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 brk_start = (unsigned long) sbrk(0);
391 CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
392 /* Increase physical memory size for exec-shield users
393 so they actually get what they asked for. This should
394 add zero for non-exec shield users */
395
396 diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
397 if(diff > 1024 * 1024){
398 printf("Adding %ld bytes to physical memory to account for "
399 "exec-shield gap\n", diff);
400 physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
401 }
402
Jeff Dike23bbd582006-07-10 04:45:06 -0700403 uml_physmem = uml_start & PAGE_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
405 /* Reserve up to 4M after the current brk */
406 uml_reserved = ROUND_4M(brk_start) + (1 << 22);
407
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700408 setup_machinename(init_utsname()->machine);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700410#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 argv1_begin = argv[1];
412 argv1_end = &argv[1][strlen(argv[1])];
413#endif
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700414
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 highmem = 0;
416 iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
417 max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
418
419 /* Zones have to begin on a 1 << MAX_ORDER page boundary,
420 * so this makes sure that's true for highmem
421 */
422 max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
423 if(physmem_size + iomem_size > max_physmem){
424 highmem = physmem_size + iomem_size - max_physmem;
425 physmem_size -= highmem;
426#ifndef CONFIG_HIGHMEM
427 highmem = 0;
428 printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
Jeff Diked9f8b622006-03-27 01:14:29 -0800429 "to %Lu bytes\n", physmem_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430#endif
431 }
432
433 high_physmem = uml_physmem + physmem_size;
434 end_iomem = high_physmem + iomem_size;
435 high_memory = (void *) end_iomem;
436
437 start_vm = VMALLOC_START;
438
439 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
440 if(init_maps(physmem_size, iomem_size, highmem)){
Jeff Diked9f8b622006-03-27 01:14:29 -0800441 printf("Failed to allocate mem_map for %Lu bytes of physical "
442 "memory and %Lu bytes of highmem\n", physmem_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 highmem);
444 exit(1);
445 }
446
447 virtmem_size = physmem_size;
448 avail = get_kmem_end() - start_vm;
449 if(physmem_size > avail) virtmem_size = avail;
450 end_vm = start_vm + virtmem_size;
451
452 if(virtmem_size < physmem_size)
Jeff Dikeae173812005-11-07 00:58:57 -0800453 printf("Kernel virtual memory size shrunk to %lu bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 virtmem_size);
455
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700456 uml_postsetup();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
458 task_protections((unsigned long) &init_thread_info);
459 os_flush_stdout();
460
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700461 return CHOOSE_MODE(start_uml_tt(), start_uml_skas());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462}
463
464extern int uml_exitcode;
465
466static int panic_exit(struct notifier_block *self, unsigned long unused1,
467 void *unused2)
468{
469 bust_spinlocks(1);
470 show_regs(&(current->thread.regs));
471 bust_spinlocks(0);
472 uml_exitcode = 1;
473 machine_halt();
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700474 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475}
476
477static struct notifier_block panic_exit_notifier = {
478 .notifier_call = panic_exit,
479 .next = NULL,
480 .priority = 0
481};
482
483void __init setup_arch(char **cmdline_p)
484{
Alan Sterne041c682006-03-27 01:16:30 -0800485 atomic_notifier_chain_register(&panic_notifier_list,
486 &panic_exit_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 paging_init();
Alon Bar-Lev19bf7e72007-02-12 00:54:23 -0800488 strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700489 *cmdline_p = command_line;
Jeff Dikeb4ffb6a2007-05-06 14:50:59 -0700490 setup_hostinfo(host_info, sizeof host_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491}
492
493void __init check_bugs(void)
494{
495 arch_check_bugs();
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700496 os_check_bugs();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497}
498
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800499void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
500{
501}
502
Theodore Tsoc61a8412006-07-03 00:24:09 -0700503#ifdef CONFIG_SMP
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800504void alternatives_smp_module_add(struct module *mod, char *name,
505 void *locks, void *locks_end,
506 void *text, void *text_end)
507{
508}
509
510void alternatives_smp_module_del(struct module *mod)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511{
512}
Theodore Tsoc61a8412006-07-03 00:24:09 -0700513#endif