blob: ecc458fe51b910d91374664660db4446723fd46d [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 "kern_util.h"
Jeff Dike4ff83ce2007-05-06 14:51:08 -070030#include "as-layout.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
Jeff Dike1d1497e2007-05-06 14:51:26 -070047/* Changed in add_arg 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
Jeff Dike1d1497e2007-05-06 14:51:26 -070061/*
62 * These fields are initialized at boot time and not changed.
63 * XXX This structure is used only in the non-SMP case. Maybe this
64 * should be moved to smp.c.
65 */
66struct cpuinfo_um boot_cpu_data = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 .loops_per_jiffy = 0,
68 .ipi_pipe = { -1, -1 }
69};
70
71unsigned long thread_saved_pc(struct task_struct *task)
72{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070073 return os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
74 task));
Linus Torvalds1da177e2005-04-16 15:20:36 -070075}
76
Jeff Dikeb4ffb6a2007-05-06 14:50:59 -070077/* Changed in setup_arch, which is called in early boot */
78static char host_info[(__NEW_UTS_LEN + 1) * 5];
79
Linus Torvalds1da177e2005-04-16 15:20:36 -070080static int show_cpuinfo(struct seq_file *m, void *v)
81{
82 int index = 0;
83
84#ifdef CONFIG_SMP
85 index = (struct cpuinfo_um *) v - cpu_data;
86 if (!cpu_online(index))
87 return 0;
88#endif
89
90 seq_printf(m, "processor\t: %d\n", index);
91 seq_printf(m, "vendor_id\t: User Mode Linux\n");
92 seq_printf(m, "model name\t: UML\n");
93 seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
94 seq_printf(m, "host\t\t: %s\n", host_info);
95 seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
96 loops_per_jiffy/(500000/HZ),
97 (loops_per_jiffy/(5000/HZ)) % 100);
98
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070099 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100}
101
102static void *c_start(struct seq_file *m, loff_t *pos)
103{
104 return *pos < NR_CPUS ? cpu_data + *pos : NULL;
105}
106
107static void *c_next(struct seq_file *m, void *v, loff_t *pos)
108{
109 ++*pos;
110 return c_start(m, pos);
111}
112
113static void c_stop(struct seq_file *m, void *v)
114{
115}
116
Jeff Dike5e7672e2006-09-27 01:50:33 -0700117const struct seq_operations cpuinfo_op = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 .start = c_start,
119 .next = c_next,
120 .stop = c_stop,
121 .show = show_cpuinfo,
122};
123
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124/* Set in linux_main */
125unsigned long host_task_size;
126unsigned long task_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127unsigned long uml_physmem;
Jeff Dike1d1497e2007-05-06 14:51:26 -0700128unsigned long uml_reserved; /* Also modified in mem_init */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129unsigned long start_vm;
130unsigned long end_vm;
Jeff Dike1d1497e2007-05-06 14:51:26 -0700131
132/* Set in uml_ncpus_setup */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133int ncpus = 1;
134
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700135#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136/* Pointer set in linux_main, the array itself is private to each thread,
137 * and changed at address space creation time so this poses no concurrency
138 * problems.
139 */
140static char *argv1_begin = NULL;
141static char *argv1_end = NULL;
142#endif
143
144/* Set in early boot */
145static int have_root __initdata = 0;
Jeff Dike1d1497e2007-05-06 14:51:26 -0700146
147/* Set in uml_mem_setup and modified in linux_main */
Jeff Dikeae173812005-11-07 00:58:57 -0800148long long physmem_size = 32 * 1024 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150void set_cmdline(char *cmd)
151{
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700152#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 char *umid, *ptr;
154
155 if(CHOOSE_MODE(honeypot, 0)) return;
156
Jeff Dike7eebe8a2006-01-06 00:19:01 -0800157 umid = get_umid();
158 if(*umid != '\0'){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 snprintf(argv1_begin,
160 (argv1_end - argv1_begin) * sizeof(*ptr),
161 "(%s) ", umid);
162 ptr = &argv1_begin[strlen(argv1_begin)];
163 }
164 else ptr = argv1_begin;
165
166 snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
167 memset(argv1_begin + strlen(argv1_begin), '\0',
168 argv1_end - argv1_begin - strlen(argv1_begin));
169#endif
170}
171
172static char *usage_string =
173"User Mode Linux v%s\n"
174" available at http://user-mode-linux.sourceforge.net/\n\n";
175
176static int __init uml_version_setup(char *line, int *add)
177{
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700178 printf("%s\n", init_utsname()->release);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 exit(0);
180
181 return 0;
182}
183
184__uml_setup("--version", uml_version_setup,
185"--version\n"
186" Prints the version number of the kernel.\n\n"
187);
188
189static int __init uml_root_setup(char *line, int *add)
190{
191 have_root = 1;
192 return 0;
193}
194
195__uml_setup("root=", uml_root_setup,
196"root=<file containing the root fs>\n"
197" This is actually used by the generic kernel in exactly the same\n"
198" way as in any other kernel. If you configure a number of block\n"
199" devices and want to boot off something other than ubd0, you \n"
200" would use something like:\n"
201" root=/dev/ubd5\n\n"
202);
203
Jeff Dikefbd55772006-02-07 12:58:40 -0800204#ifndef CONFIG_MODE_TT
205
206static int __init no_skas_debug_setup(char *line, int *add)
207{
208 printf("'debug' is not necessary to gdb UML in skas mode - run \n");
209 printf("'gdb linux' and disable CONFIG_CMDLINE_ON_HOST if gdb \n");
210 printf("doesn't work as expected\n");
211
212 return 0;
213}
214
215__uml_setup("debug", no_skas_debug_setup,
216"debug\n"
217" this flag is not needed to run gdb on UML in skas mode\n\n"
218);
219
220#endif
221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222#ifdef CONFIG_SMP
223static int __init uml_ncpus_setup(char *line, int *add)
224{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700225 if (!sscanf(line, "%d", &ncpus)) {
226 printf("Couldn't parse [%s]\n", line);
227 return -1;
228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700230 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231}
232
233__uml_setup("ncpus=", uml_ncpus_setup,
234"ncpus=<# of desired CPUs>\n"
235" This tells an SMP kernel how many virtual processors to start.\n\n"
236);
237#endif
238
239static int force_tt = 0;
240
241#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
242#define DEFAULT_TT 0
243
244static int __init mode_tt_setup(char *line, int *add)
245{
246 force_tt = 1;
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700247 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248}
249
250#else
251#ifdef CONFIG_MODE_SKAS
252
253#define DEFAULT_TT 0
254
255static int __init mode_tt_setup(char *line, int *add)
256{
257 printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700258 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259}
260
261#else
262#ifdef CONFIG_MODE_TT
263
264#define DEFAULT_TT 1
265
266static int __init mode_tt_setup(char *line, int *add)
267{
268 printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700269 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270}
271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272#endif
273#endif
274#endif
275
276__uml_setup("mode=tt", mode_tt_setup,
277"mode=tt\n"
278" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
279" forces UML to run in tt (tracing thread) mode. It is not the default\n"
280" because it's slower and less secure than skas mode.\n\n"
281);
282
283int mode_tt = DEFAULT_TT;
284
285static int __init Usage(char *line, int *add)
286{
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700287 const char **p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700289 printf(usage_string, init_utsname()->release);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700290 p = &__uml_help_start;
291 while (p < &__uml_help_end) {
292 printf("%s", *p);
293 p++;
294 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 return 0;
297}
298
299__uml_setup("--help", Usage,
300"--help\n"
301" Prints this message.\n\n"
302);
303
304static int __init uml_checksetup(char *line, int *add)
305{
306 struct uml_param *p;
307
308 p = &__uml_setup_start;
309 while(p < &__uml_setup_end) {
310 int n;
311
312 n = strlen(p->str);
313 if(!strncmp(line, p->str, n)){
314 if (p->setup_func(line + n, add)) return 1;
315 }
316 p++;
317 }
318 return 0;
319}
320
321static void __init uml_postsetup(void)
322{
323 initcall_t *p;
324
325 p = &__uml_postsetup_start;
326 while(p < &__uml_postsetup_end){
327 (*p)();
328 p++;
329 }
330 return;
331}
332
333/* Set during early boot */
334unsigned long brk_start;
335unsigned long end_iomem;
336EXPORT_SYMBOL(end_iomem);
337
338#define MIN_VMALLOC (32 * 1024 * 1024)
339
Jeff Dike23bbd582006-07-10 04:45:06 -0700340extern char __binary_start;
341
Alon Bar-Lev7a3a06d02007-02-12 00:54:26 -0800342int __init linux_main(int argc, char **argv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
344 unsigned long avail, diff;
345 unsigned long virtmem_size, max_physmem;
346 unsigned int i, add;
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700347 char * mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 for (i = 1; i < argc; i++){
350 if((i == 1) && (argv[i][0] == ' ')) continue;
351 add = 1;
352 uml_checksetup(argv[i], &add);
353 if (add)
354 add_arg(argv[i]);
355 }
356 if(have_root == 0)
357 add_arg(DEFAULT_COMMAND_LINE);
358
Gennady Sharapov60d339f2005-09-03 15:57:47 -0700359 os_early_checks();
Paolo 'Blaisorblade' Giarrusso89236482005-09-30 11:59:00 -0700360 if (force_tt)
361 clear_can_do_skas();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 mode_tt = force_tt ? 1 : !can_do_skas();
363#ifndef CONFIG_MODE_TT
364 if (mode_tt) {
365 /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
366 * can_do_skas() returned 0, and the message is correct. */
367 printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
368 exit(1);
369 }
370#endif
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700371
372#ifndef CONFIG_MODE_SKAS
373 mode = "TT";
374#else
375 /* Show to the user the result of selection */
376 if (mode_tt)
377 mode = "TT";
378 else if (proc_mm && ptrace_faultinfo)
379 mode = "SKAS3";
380 else
381 mode = "SKAS0";
382#endif
383
384 printf("UML running in %s mode\n", mode);
385
Jeff Dike23bbd582006-07-10 04:45:06 -0700386 host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt,
387 set_task_sizes_skas, &task_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800389 /*
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700390 * Setting up handlers to 'sig_info' struct
391 */
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800392 os_fill_handlinfo(handlinfo_kern);
393
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 brk_start = (unsigned long) sbrk(0);
395 CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
396 /* Increase physical memory size for exec-shield users
397 so they actually get what they asked for. This should
398 add zero for non-exec shield users */
399
400 diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
401 if(diff > 1024 * 1024){
402 printf("Adding %ld bytes to physical memory to account for "
403 "exec-shield gap\n", diff);
404 physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
405 }
406
Jeff Dike1d1497e2007-05-06 14:51:26 -0700407 uml_physmem = (unsigned long) &__binary_start & PAGE_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
409 /* Reserve up to 4M after the current brk */
410 uml_reserved = ROUND_4M(brk_start) + (1 << 22);
411
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700412 setup_machinename(init_utsname()->machine);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700414#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 argv1_begin = argv[1];
416 argv1_end = &argv[1][strlen(argv[1])];
417#endif
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700418
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 highmem = 0;
420 iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
421 max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
422
423 /* Zones have to begin on a 1 << MAX_ORDER page boundary,
424 * so this makes sure that's true for highmem
425 */
426 max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
427 if(physmem_size + iomem_size > max_physmem){
428 highmem = physmem_size + iomem_size - max_physmem;
429 physmem_size -= highmem;
430#ifndef CONFIG_HIGHMEM
431 highmem = 0;
432 printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
Jeff Diked9f8b622006-03-27 01:14:29 -0800433 "to %Lu bytes\n", physmem_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434#endif
435 }
436
437 high_physmem = uml_physmem + physmem_size;
438 end_iomem = high_physmem + iomem_size;
439 high_memory = (void *) end_iomem;
440
441 start_vm = VMALLOC_START;
442
443 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
444 if(init_maps(physmem_size, iomem_size, highmem)){
Jeff Diked9f8b622006-03-27 01:14:29 -0800445 printf("Failed to allocate mem_map for %Lu bytes of physical "
446 "memory and %Lu bytes of highmem\n", physmem_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 highmem);
448 exit(1);
449 }
450
451 virtmem_size = physmem_size;
452 avail = get_kmem_end() - start_vm;
453 if(physmem_size > avail) virtmem_size = avail;
454 end_vm = start_vm + virtmem_size;
455
456 if(virtmem_size < physmem_size)
Jeff Dikeae173812005-11-07 00:58:57 -0800457 printf("Kernel virtual memory size shrunk to %lu bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 virtmem_size);
459
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700460 uml_postsetup();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Jeff Dike57598fd2007-05-10 22:22:30 -0700462 stack_protections((unsigned long) &init_thread_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 os_flush_stdout();
464
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700465 return CHOOSE_MODE(start_uml_tt(), start_uml_skas());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466}
467
468extern int uml_exitcode;
469
470static int panic_exit(struct notifier_block *self, unsigned long unused1,
471 void *unused2)
472{
473 bust_spinlocks(1);
474 show_regs(&(current->thread.regs));
475 bust_spinlocks(0);
476 uml_exitcode = 1;
Jeff Dike63843c22007-05-06 14:51:39 -0700477 os_dump_core();
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700478 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479}
480
481static struct notifier_block panic_exit_notifier = {
482 .notifier_call = panic_exit,
483 .next = NULL,
484 .priority = 0
485};
486
487void __init setup_arch(char **cmdline_p)
488{
Alan Sterne041c682006-03-27 01:16:30 -0800489 atomic_notifier_chain_register(&panic_notifier_list,
490 &panic_exit_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 paging_init();
Alon Bar-Lev19bf7e72007-02-12 00:54:23 -0800492 strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700493 *cmdline_p = command_line;
Jeff Dikeb4ffb6a2007-05-06 14:50:59 -0700494 setup_hostinfo(host_info, sizeof host_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495}
496
497void __init check_bugs(void)
498{
499 arch_check_bugs();
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700500 os_check_bugs();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501}
502
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800503void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
504{
505}
506
Theodore Tsoc61a8412006-07-03 00:24:09 -0700507#ifdef CONFIG_SMP
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800508void alternatives_smp_module_add(struct module *mod, char *name,
509 void *locks, void *locks_end,
510 void *text, void *text_end)
511{
512}
513
514void alternatives_smp_module_del(struct module *mod)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515{
516}
Theodore Tsoc61a8412006-07-03 00:24:09 -0700517#endif