blob: 7896cf98232df1a06c6593957e24597b8dbb7e04 [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
6#include "linux/config.h"
7#include "linux/kernel.h"
8#include "linux/sched.h"
9#include "linux/notifier.h"
10#include "linux/mm.h"
11#include "linux/types.h"
12#include "linux/tty.h"
13#include "linux/init.h"
14#include "linux/bootmem.h"
15#include "linux/spinlock.h"
16#include "linux/utsname.h"
17#include "linux/sysrq.h"
18#include "linux/seq_file.h"
19#include "linux/delay.h"
20#include "linux/module.h"
21#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"
34#include "umid.h"
35#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 */
Jeff Dike16c11162005-05-06 21:30:45 -070048static char command_line[COMMAND_LINE_SIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Jeff Dike16c11162005-05-06 21:30:45 -070050static void 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{
68 return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
69 task)));
70}
71
72static int show_cpuinfo(struct seq_file *m, void *v)
73{
74 int index = 0;
75
76#ifdef CONFIG_SMP
77 index = (struct cpuinfo_um *) v - cpu_data;
78 if (!cpu_online(index))
79 return 0;
80#endif
81
82 seq_printf(m, "processor\t: %d\n", index);
83 seq_printf(m, "vendor_id\t: User Mode Linux\n");
84 seq_printf(m, "model name\t: UML\n");
85 seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
86 seq_printf(m, "host\t\t: %s\n", host_info);
87 seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
88 loops_per_jiffy/(500000/HZ),
89 (loops_per_jiffy/(5000/HZ)) % 100);
90
91 return(0);
92}
93
94static void *c_start(struct seq_file *m, loff_t *pos)
95{
96 return *pos < NR_CPUS ? cpu_data + *pos : NULL;
97}
98
99static void *c_next(struct seq_file *m, void *v, loff_t *pos)
100{
101 ++*pos;
102 return c_start(m, pos);
103}
104
105static void c_stop(struct seq_file *m, void *v)
106{
107}
108
109struct seq_operations cpuinfo_op = {
110 .start = c_start,
111 .next = c_next,
112 .stop = c_stop,
113 .show = show_cpuinfo,
114};
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116/* Set in linux_main */
117unsigned long host_task_size;
118unsigned long task_size;
119
120unsigned long uml_start;
121
122/* Set in early boot */
123unsigned long uml_physmem;
124unsigned long uml_reserved;
125unsigned long start_vm;
126unsigned long end_vm;
127int ncpus = 1;
128
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700129#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130/* Pointer set in linux_main, the array itself is private to each thread,
131 * and changed at address space creation time so this poses no concurrency
132 * problems.
133 */
134static char *argv1_begin = NULL;
135static char *argv1_end = NULL;
136#endif
137
138/* Set in early boot */
139static int have_root __initdata = 0;
Jeff Dikeae173812005-11-07 00:58:57 -0800140long long physmem_size = 32 * 1024 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142void set_cmdline(char *cmd)
143{
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700144#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 char *umid, *ptr;
146
147 if(CHOOSE_MODE(honeypot, 0)) return;
148
Jeff Dike7eebe8a2006-01-06 00:19:01 -0800149 umid = get_umid();
150 if(*umid != '\0'){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 snprintf(argv1_begin,
152 (argv1_end - argv1_begin) * sizeof(*ptr),
153 "(%s) ", umid);
154 ptr = &argv1_begin[strlen(argv1_begin)];
155 }
156 else ptr = argv1_begin;
157
158 snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
159 memset(argv1_begin + strlen(argv1_begin), '\0',
160 argv1_end - argv1_begin - strlen(argv1_begin));
161#endif
162}
163
164static char *usage_string =
165"User Mode Linux v%s\n"
166" available at http://user-mode-linux.sourceforge.net/\n\n";
167
168static int __init uml_version_setup(char *line, int *add)
169{
170 printf("%s\n", system_utsname.release);
171 exit(0);
172
173 return 0;
174}
175
176__uml_setup("--version", uml_version_setup,
177"--version\n"
178" Prints the version number of the kernel.\n\n"
179);
180
181static int __init uml_root_setup(char *line, int *add)
182{
183 have_root = 1;
184 return 0;
185}
186
187__uml_setup("root=", uml_root_setup,
188"root=<file containing the root fs>\n"
189" This is actually used by the generic kernel in exactly the same\n"
190" way as in any other kernel. If you configure a number of block\n"
191" devices and want to boot off something other than ubd0, you \n"
192" would use something like:\n"
193" root=/dev/ubd5\n\n"
194);
195
Jeff Dikefbd55772006-02-07 12:58:40 -0800196#ifndef CONFIG_MODE_TT
197
198static int __init no_skas_debug_setup(char *line, int *add)
199{
200 printf("'debug' is not necessary to gdb UML in skas mode - run \n");
201 printf("'gdb linux' and disable CONFIG_CMDLINE_ON_HOST if gdb \n");
202 printf("doesn't work as expected\n");
203
204 return 0;
205}
206
207__uml_setup("debug", no_skas_debug_setup,
208"debug\n"
209" this flag is not needed to run gdb on UML in skas mode\n\n"
210);
211
212#endif
213
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214#ifdef CONFIG_SMP
215static int __init uml_ncpus_setup(char *line, int *add)
216{
217 if (!sscanf(line, "%d", &ncpus)) {
218 printf("Couldn't parse [%s]\n", line);
219 return -1;
220 }
221
222 return 0;
223}
224
225__uml_setup("ncpus=", uml_ncpus_setup,
226"ncpus=<# of desired CPUs>\n"
227" This tells an SMP kernel how many virtual processors to start.\n\n"
228);
229#endif
230
231static int force_tt = 0;
232
233#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
234#define DEFAULT_TT 0
235
236static int __init mode_tt_setup(char *line, int *add)
237{
238 force_tt = 1;
239 return(0);
240}
241
242#else
243#ifdef CONFIG_MODE_SKAS
244
245#define DEFAULT_TT 0
246
247static int __init mode_tt_setup(char *line, int *add)
248{
249 printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
250 return(0);
251}
252
253#else
254#ifdef CONFIG_MODE_TT
255
256#define DEFAULT_TT 1
257
258static int __init mode_tt_setup(char *line, int *add)
259{
260 printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
261 return(0);
262}
263
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264#endif
265#endif
266#endif
267
268__uml_setup("mode=tt", mode_tt_setup,
269"mode=tt\n"
270" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
271" forces UML to run in tt (tracing thread) mode. It is not the default\n"
272" because it's slower and less secure than skas mode.\n\n"
273);
274
275int mode_tt = DEFAULT_TT;
276
277static int __init Usage(char *line, int *add)
278{
279 const char **p;
280
281 printf(usage_string, system_utsname.release);
282 p = &__uml_help_start;
283 while (p < &__uml_help_end) {
284 printf("%s", *p);
285 p++;
286 }
287 exit(0);
288
289 return 0;
290}
291
292__uml_setup("--help", Usage,
293"--help\n"
294" Prints this message.\n\n"
295);
296
297static int __init uml_checksetup(char *line, int *add)
298{
299 struct uml_param *p;
300
301 p = &__uml_setup_start;
302 while(p < &__uml_setup_end) {
303 int n;
304
305 n = strlen(p->str);
306 if(!strncmp(line, p->str, n)){
307 if (p->setup_func(line + n, add)) return 1;
308 }
309 p++;
310 }
311 return 0;
312}
313
314static void __init uml_postsetup(void)
315{
316 initcall_t *p;
317
318 p = &__uml_postsetup_start;
319 while(p < &__uml_postsetup_end){
320 (*p)();
321 p++;
322 }
323 return;
324}
325
326/* Set during early boot */
327unsigned long brk_start;
328unsigned long end_iomem;
329EXPORT_SYMBOL(end_iomem);
330
331#define MIN_VMALLOC (32 * 1024 * 1024)
332
Jeff Dike23bbd582006-07-10 04:45:06 -0700333extern char __binary_start;
334
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335int linux_main(int argc, char **argv)
336{
337 unsigned long avail, diff;
338 unsigned long virtmem_size, max_physmem;
339 unsigned int i, add;
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700340 char * mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
342 for (i = 1; i < argc; i++){
343 if((i == 1) && (argv[i][0] == ' ')) continue;
344 add = 1;
345 uml_checksetup(argv[i], &add);
346 if (add)
347 add_arg(argv[i]);
348 }
349 if(have_root == 0)
350 add_arg(DEFAULT_COMMAND_LINE);
351
Gennady Sharapov60d339f2005-09-03 15:57:47 -0700352 os_early_checks();
Paolo 'Blaisorblade' Giarrusso89236482005-09-30 11:59:00 -0700353 if (force_tt)
354 clear_can_do_skas();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 mode_tt = force_tt ? 1 : !can_do_skas();
356#ifndef CONFIG_MODE_TT
357 if (mode_tt) {
358 /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
359 * can_do_skas() returned 0, and the message is correct. */
360 printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
361 exit(1);
362 }
363#endif
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700364
365#ifndef CONFIG_MODE_SKAS
366 mode = "TT";
367#else
368 /* Show to the user the result of selection */
369 if (mode_tt)
370 mode = "TT";
371 else if (proc_mm && ptrace_faultinfo)
372 mode = "SKAS3";
373 else
374 mode = "SKAS0";
375#endif
376
377 printf("UML running in %s mode\n", mode);
378
Jeff Dike23bbd582006-07-10 04:45:06 -0700379 uml_start = (unsigned long) &__binary_start;
380 host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt,
381 set_task_sizes_skas, &task_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800383 /*
384 * Setting up handlers to 'sig_info' struct
385 */
386 os_fill_handlinfo(handlinfo_kern);
387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 brk_start = (unsigned long) sbrk(0);
389 CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
390 /* Increase physical memory size for exec-shield users
391 so they actually get what they asked for. This should
392 add zero for non-exec shield users */
393
394 diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
395 if(diff > 1024 * 1024){
396 printf("Adding %ld bytes to physical memory to account for "
397 "exec-shield gap\n", diff);
398 physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
399 }
400
Jeff Dike23bbd582006-07-10 04:45:06 -0700401 uml_physmem = uml_start & PAGE_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
403 /* Reserve up to 4M after the current brk */
404 uml_reserved = ROUND_4M(brk_start) + (1 << 22);
405
406 setup_machinename(system_utsname.machine);
407
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700408#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 argv1_begin = argv[1];
410 argv1_end = &argv[1][strlen(argv[1])];
411#endif
412
413 highmem = 0;
414 iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
415 max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
416
417 /* Zones have to begin on a 1 << MAX_ORDER page boundary,
418 * so this makes sure that's true for highmem
419 */
420 max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
421 if(physmem_size + iomem_size > max_physmem){
422 highmem = physmem_size + iomem_size - max_physmem;
423 physmem_size -= highmem;
424#ifndef CONFIG_HIGHMEM
425 highmem = 0;
426 printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
Jeff Diked9f8b622006-03-27 01:14:29 -0800427 "to %Lu bytes\n", physmem_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428#endif
429 }
430
431 high_physmem = uml_physmem + physmem_size;
432 end_iomem = high_physmem + iomem_size;
433 high_memory = (void *) end_iomem;
434
435 start_vm = VMALLOC_START;
436
437 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
438 if(init_maps(physmem_size, iomem_size, highmem)){
Jeff Diked9f8b622006-03-27 01:14:29 -0800439 printf("Failed to allocate mem_map for %Lu bytes of physical "
440 "memory and %Lu bytes of highmem\n", physmem_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 highmem);
442 exit(1);
443 }
444
445 virtmem_size = physmem_size;
446 avail = get_kmem_end() - start_vm;
447 if(physmem_size > avail) virtmem_size = avail;
448 end_vm = start_vm + virtmem_size;
449
450 if(virtmem_size < physmem_size)
Jeff Dikeae173812005-11-07 00:58:57 -0800451 printf("Kernel virtual memory size shrunk to %lu bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 virtmem_size);
453
454 uml_postsetup();
455
456 task_protections((unsigned long) &init_thread_info);
457 os_flush_stdout();
458
459 return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
460}
461
462extern int uml_exitcode;
463
464static int panic_exit(struct notifier_block *self, unsigned long unused1,
465 void *unused2)
466{
467 bust_spinlocks(1);
468 show_regs(&(current->thread.regs));
469 bust_spinlocks(0);
470 uml_exitcode = 1;
471 machine_halt();
472 return(0);
473}
474
475static struct notifier_block panic_exit_notifier = {
476 .notifier_call = panic_exit,
477 .next = NULL,
478 .priority = 0
479};
480
481void __init setup_arch(char **cmdline_p)
482{
Alan Sterne041c682006-03-27 01:16:30 -0800483 atomic_notifier_chain_register(&panic_notifier_list,
484 &panic_exit_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 paging_init();
Jeff Dike16c11162005-05-06 21:30:45 -0700486 strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 *cmdline_p = command_line;
488 setup_hostinfo();
489}
490
491void __init check_bugs(void)
492{
493 arch_check_bugs();
Jeff Dike8e367062006-03-27 01:14:32 -0800494 os_check_bugs();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495}
496
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800497void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
498{
499}
500
Theodore Tsoc61a8412006-07-03 00:24:09 -0700501#ifdef CONFIG_SMP
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800502void alternatives_smp_module_add(struct module *mod, char *name,
503 void *locks, void *locks_end,
504 void *text, void *text_end)
505{
506}
507
508void alternatives_smp_module_del(struct module *mod)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509{
510}
Theodore Tsoc61a8412006-07-03 00:24:09 -0700511#endif