blob: 20684c04d5d5a3bc8101d7280405967d184e1b90 [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 Dike4ff83ce2007-05-06 14:51:08 -070031#include "as-layout.h"
Jeff Dikeeb830752007-05-06 14:51:07 -070032#include "arch.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include "kern.h"
34#include "mem_user.h"
35#include "mem.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include "initrd.h"
37#include "init.h"
38#include "os.h"
39#include "choose-mode.h"
40#include "mode_kern.h"
41#include "mode.h"
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -070042#ifdef UML_CONFIG_MODE_SKAS
43#include "skas.h"
44#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46#define DEFAULT_COMMAND_LINE "root=98:0"
47
48/* Changed in linux_main and setup_arch, which run before SMP is started */
Alon Bar-Lev7a3a06d02007-02-12 00:54:26 -080049static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
Alon Bar-Lev7a3a06d02007-02-12 00:54:26 -080051static void __init add_arg(char *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070052{
53 if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
54 printf("add_arg: Too many command line arguments!\n");
55 exit(1);
56 }
57 if(strlen(command_line) > 0)
58 strcat(command_line, " ");
59 strcat(command_line, arg);
60}
61
62struct cpuinfo_um boot_cpu_data = {
63 .loops_per_jiffy = 0,
64 .ipi_pipe = { -1, -1 }
65};
66
67unsigned long thread_saved_pc(struct task_struct *task)
68{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070069 return os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
70 task));
Linus Torvalds1da177e2005-04-16 15:20:36 -070071}
72
Jeff Dikeb4ffb6a2007-05-06 14:50:59 -070073/* Changed in setup_arch, which is called in early boot */
74static char host_info[(__NEW_UTS_LEN + 1) * 5];
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static int show_cpuinfo(struct seq_file *m, void *v)
77{
78 int index = 0;
79
80#ifdef CONFIG_SMP
81 index = (struct cpuinfo_um *) v - cpu_data;
82 if (!cpu_online(index))
83 return 0;
84#endif
85
86 seq_printf(m, "processor\t: %d\n", index);
87 seq_printf(m, "vendor_id\t: User Mode Linux\n");
88 seq_printf(m, "model name\t: UML\n");
89 seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
90 seq_printf(m, "host\t\t: %s\n", host_info);
91 seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
92 loops_per_jiffy/(500000/HZ),
93 (loops_per_jiffy/(5000/HZ)) % 100);
94
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070095 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096}
97
98static void *c_start(struct seq_file *m, loff_t *pos)
99{
100 return *pos < NR_CPUS ? cpu_data + *pos : NULL;
101}
102
103static void *c_next(struct seq_file *m, void *v, loff_t *pos)
104{
105 ++*pos;
106 return c_start(m, pos);
107}
108
109static void c_stop(struct seq_file *m, void *v)
110{
111}
112
Jeff Dike5e7672e2006-09-27 01:50:33 -0700113const struct seq_operations cpuinfo_op = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 .start = c_start,
115 .next = c_next,
116 .stop = c_stop,
117 .show = show_cpuinfo,
118};
119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120/* Set in linux_main */
121unsigned long host_task_size;
122unsigned long task_size;
123
124unsigned long uml_start;
125
126/* Set in early boot */
127unsigned long uml_physmem;
128unsigned long uml_reserved;
129unsigned long start_vm;
130unsigned long end_vm;
131int ncpus = 1;
132
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700133#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134/* Pointer set in linux_main, the array itself is private to each thread,
135 * and changed at address space creation time so this poses no concurrency
136 * problems.
137 */
138static char *argv1_begin = NULL;
139static char *argv1_end = NULL;
140#endif
141
142/* Set in early boot */
143static int have_root __initdata = 0;
Jeff Dikeae173812005-11-07 00:58:57 -0800144long long physmem_size = 32 * 1024 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
146void set_cmdline(char *cmd)
147{
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700148#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 char *umid, *ptr;
150
151 if(CHOOSE_MODE(honeypot, 0)) return;
152
Jeff Dike7eebe8a2006-01-06 00:19:01 -0800153 umid = get_umid();
154 if(*umid != '\0'){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 snprintf(argv1_begin,
156 (argv1_end - argv1_begin) * sizeof(*ptr),
157 "(%s) ", umid);
158 ptr = &argv1_begin[strlen(argv1_begin)];
159 }
160 else ptr = argv1_begin;
161
162 snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
163 memset(argv1_begin + strlen(argv1_begin), '\0',
164 argv1_end - argv1_begin - strlen(argv1_begin));
165#endif
166}
167
168static char *usage_string =
169"User Mode Linux v%s\n"
170" available at http://user-mode-linux.sourceforge.net/\n\n";
171
172static int __init uml_version_setup(char *line, int *add)
173{
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700174 printf("%s\n", init_utsname()->release);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 exit(0);
176
177 return 0;
178}
179
180__uml_setup("--version", uml_version_setup,
181"--version\n"
182" Prints the version number of the kernel.\n\n"
183);
184
185static int __init uml_root_setup(char *line, int *add)
186{
187 have_root = 1;
188 return 0;
189}
190
191__uml_setup("root=", uml_root_setup,
192"root=<file containing the root fs>\n"
193" This is actually used by the generic kernel in exactly the same\n"
194" way as in any other kernel. If you configure a number of block\n"
195" devices and want to boot off something other than ubd0, you \n"
196" would use something like:\n"
197" root=/dev/ubd5\n\n"
198);
199
Jeff Dikefbd55772006-02-07 12:58:40 -0800200#ifndef CONFIG_MODE_TT
201
202static int __init no_skas_debug_setup(char *line, int *add)
203{
204 printf("'debug' is not necessary to gdb UML in skas mode - run \n");
205 printf("'gdb linux' and disable CONFIG_CMDLINE_ON_HOST if gdb \n");
206 printf("doesn't work as expected\n");
207
208 return 0;
209}
210
211__uml_setup("debug", no_skas_debug_setup,
212"debug\n"
213" this flag is not needed to run gdb on UML in skas mode\n\n"
214);
215
216#endif
217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218#ifdef CONFIG_SMP
219static int __init uml_ncpus_setup(char *line, int *add)
220{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700221 if (!sscanf(line, "%d", &ncpus)) {
222 printf("Couldn't parse [%s]\n", line);
223 return -1;
224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700226 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227}
228
229__uml_setup("ncpus=", uml_ncpus_setup,
230"ncpus=<# of desired CPUs>\n"
231" This tells an SMP kernel how many virtual processors to start.\n\n"
232);
233#endif
234
235static int force_tt = 0;
236
237#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
238#define DEFAULT_TT 0
239
240static int __init mode_tt_setup(char *line, int *add)
241{
242 force_tt = 1;
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700243 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244}
245
246#else
247#ifdef CONFIG_MODE_SKAS
248
249#define DEFAULT_TT 0
250
251static int __init mode_tt_setup(char *line, int *add)
252{
253 printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700254 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255}
256
257#else
258#ifdef CONFIG_MODE_TT
259
260#define DEFAULT_TT 1
261
262static int __init mode_tt_setup(char *line, int *add)
263{
264 printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700265 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266}
267
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268#endif
269#endif
270#endif
271
272__uml_setup("mode=tt", mode_tt_setup,
273"mode=tt\n"
274" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
275" forces UML to run in tt (tracing thread) mode. It is not the default\n"
276" because it's slower and less secure than skas mode.\n\n"
277);
278
279int mode_tt = DEFAULT_TT;
280
281static int __init Usage(char *line, int *add)
282{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700283 const char **p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700285 printf(usage_string, init_utsname()->release);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700286 p = &__uml_help_start;
287 while (p < &__uml_help_end) {
288 printf("%s", *p);
289 p++;
290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 return 0;
293}
294
295__uml_setup("--help", Usage,
296"--help\n"
297" Prints this message.\n\n"
298);
299
300static int __init uml_checksetup(char *line, int *add)
301{
302 struct uml_param *p;
303
304 p = &__uml_setup_start;
305 while(p < &__uml_setup_end) {
306 int n;
307
308 n = strlen(p->str);
309 if(!strncmp(line, p->str, n)){
310 if (p->setup_func(line + n, add)) return 1;
311 }
312 p++;
313 }
314 return 0;
315}
316
317static void __init uml_postsetup(void)
318{
319 initcall_t *p;
320
321 p = &__uml_postsetup_start;
322 while(p < &__uml_postsetup_end){
323 (*p)();
324 p++;
325 }
326 return;
327}
328
329/* Set during early boot */
330unsigned long brk_start;
331unsigned long end_iomem;
332EXPORT_SYMBOL(end_iomem);
333
334#define MIN_VMALLOC (32 * 1024 * 1024)
335
Jeff Dike23bbd582006-07-10 04:45:06 -0700336extern char __binary_start;
337
Alon Bar-Lev7a3a06d02007-02-12 00:54:26 -0800338int __init linux_main(int argc, char **argv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
340 unsigned long avail, diff;
341 unsigned long virtmem_size, max_physmem;
342 unsigned int i, add;
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700343 char * mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 for (i = 1; i < argc; i++){
346 if((i == 1) && (argv[i][0] == ' ')) continue;
347 add = 1;
348 uml_checksetup(argv[i], &add);
349 if (add)
350 add_arg(argv[i]);
351 }
352 if(have_root == 0)
353 add_arg(DEFAULT_COMMAND_LINE);
354
Gennady Sharapov60d339f2005-09-03 15:57:47 -0700355 os_early_checks();
Paolo 'Blaisorblade' Giarrusso89236482005-09-30 11:59:00 -0700356 if (force_tt)
357 clear_can_do_skas();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 mode_tt = force_tt ? 1 : !can_do_skas();
359#ifndef CONFIG_MODE_TT
360 if (mode_tt) {
361 /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
362 * can_do_skas() returned 0, and the message is correct. */
363 printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
364 exit(1);
365 }
366#endif
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700367
368#ifndef CONFIG_MODE_SKAS
369 mode = "TT";
370#else
371 /* Show to the user the result of selection */
372 if (mode_tt)
373 mode = "TT";
374 else if (proc_mm && ptrace_faultinfo)
375 mode = "SKAS3";
376 else
377 mode = "SKAS0";
378#endif
379
380 printf("UML running in %s mode\n", mode);
381
Jeff Dike23bbd582006-07-10 04:45:06 -0700382 uml_start = (unsigned long) &__binary_start;
383 host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt,
384 set_task_sizes_skas, &task_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800386 /*
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700387 * Setting up handlers to 'sig_info' struct
388 */
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800389 os_fill_handlinfo(handlinfo_kern);
390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 brk_start = (unsigned long) sbrk(0);
392 CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
393 /* Increase physical memory size for exec-shield users
394 so they actually get what they asked for. This should
395 add zero for non-exec shield users */
396
397 diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
398 if(diff > 1024 * 1024){
399 printf("Adding %ld bytes to physical memory to account for "
400 "exec-shield gap\n", diff);
401 physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
402 }
403
Jeff Dike23bbd582006-07-10 04:45:06 -0700404 uml_physmem = uml_start & PAGE_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
406 /* Reserve up to 4M after the current brk */
407 uml_reserved = ROUND_4M(brk_start) + (1 << 22);
408
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700409 setup_machinename(init_utsname()->machine);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700411#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 argv1_begin = argv[1];
413 argv1_end = &argv[1][strlen(argv[1])];
414#endif
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700415
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 highmem = 0;
417 iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
418 max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
419
420 /* Zones have to begin on a 1 << MAX_ORDER page boundary,
421 * so this makes sure that's true for highmem
422 */
423 max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
424 if(physmem_size + iomem_size > max_physmem){
425 highmem = physmem_size + iomem_size - max_physmem;
426 physmem_size -= highmem;
427#ifndef CONFIG_HIGHMEM
428 highmem = 0;
429 printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
Jeff Diked9f8b622006-03-27 01:14:29 -0800430 "to %Lu bytes\n", physmem_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431#endif
432 }
433
434 high_physmem = uml_physmem + physmem_size;
435 end_iomem = high_physmem + iomem_size;
436 high_memory = (void *) end_iomem;
437
438 start_vm = VMALLOC_START;
439
440 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
441 if(init_maps(physmem_size, iomem_size, highmem)){
Jeff Diked9f8b622006-03-27 01:14:29 -0800442 printf("Failed to allocate mem_map for %Lu bytes of physical "
443 "memory and %Lu bytes of highmem\n", physmem_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 highmem);
445 exit(1);
446 }
447
448 virtmem_size = physmem_size;
449 avail = get_kmem_end() - start_vm;
450 if(physmem_size > avail) virtmem_size = avail;
451 end_vm = start_vm + virtmem_size;
452
453 if(virtmem_size < physmem_size)
Jeff Dikeae173812005-11-07 00:58:57 -0800454 printf("Kernel virtual memory size shrunk to %lu bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 virtmem_size);
456
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700457 uml_postsetup();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
459 task_protections((unsigned long) &init_thread_info);
460 os_flush_stdout();
461
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700462 return CHOOSE_MODE(start_uml_tt(), start_uml_skas());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463}
464
465extern int uml_exitcode;
466
467static int panic_exit(struct notifier_block *self, unsigned long unused1,
468 void *unused2)
469{
470 bust_spinlocks(1);
471 show_regs(&(current->thread.regs));
472 bust_spinlocks(0);
473 uml_exitcode = 1;
474 machine_halt();
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700475 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476}
477
478static struct notifier_block panic_exit_notifier = {
479 .notifier_call = panic_exit,
480 .next = NULL,
481 .priority = 0
482};
483
484void __init setup_arch(char **cmdline_p)
485{
Alan Sterne041c682006-03-27 01:16:30 -0800486 atomic_notifier_chain_register(&panic_notifier_list,
487 &panic_exit_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 paging_init();
Alon Bar-Lev19bf7e72007-02-12 00:54:23 -0800489 strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700490 *cmdline_p = command_line;
Jeff Dikeb4ffb6a2007-05-06 14:50:59 -0700491 setup_hostinfo(host_info, sizeof host_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492}
493
494void __init check_bugs(void)
495{
496 arch_check_bugs();
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700497 os_check_bugs();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498}
499
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800500void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
501{
502}
503
Theodore Tsoc61a8412006-07-03 00:24:09 -0700504#ifdef CONFIG_SMP
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800505void alternatives_smp_module_add(struct module *mod, char *name,
506 void *locks, void *locks_end,
507 void *text, void *text_end)
508{
509}
510
511void alternatives_smp_module_del(struct module *mod)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
513}
Theodore Tsoc61a8412006-07-03 00:24:09 -0700514#endif