blob: e2d3ca445ef57388f848f79174135757f34f7c36 [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
196#ifdef CONFIG_SMP
197static int __init uml_ncpus_setup(char *line, int *add)
198{
199 if (!sscanf(line, "%d", &ncpus)) {
200 printf("Couldn't parse [%s]\n", line);
201 return -1;
202 }
203
204 return 0;
205}
206
207__uml_setup("ncpus=", uml_ncpus_setup,
208"ncpus=<# of desired CPUs>\n"
209" This tells an SMP kernel how many virtual processors to start.\n\n"
210);
211#endif
212
213static int force_tt = 0;
214
215#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
216#define DEFAULT_TT 0
217
218static int __init mode_tt_setup(char *line, int *add)
219{
220 force_tt = 1;
221 return(0);
222}
223
224#else
225#ifdef CONFIG_MODE_SKAS
226
227#define DEFAULT_TT 0
228
229static int __init mode_tt_setup(char *line, int *add)
230{
231 printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
232 return(0);
233}
234
235#else
236#ifdef CONFIG_MODE_TT
237
238#define DEFAULT_TT 1
239
240static int __init mode_tt_setup(char *line, int *add)
241{
242 printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
243 return(0);
244}
245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246#endif
247#endif
248#endif
249
250__uml_setup("mode=tt", mode_tt_setup,
251"mode=tt\n"
252" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
253" forces UML to run in tt (tracing thread) mode. It is not the default\n"
254" because it's slower and less secure than skas mode.\n\n"
255);
256
257int mode_tt = DEFAULT_TT;
258
259static int __init Usage(char *line, int *add)
260{
261 const char **p;
262
263 printf(usage_string, system_utsname.release);
264 p = &__uml_help_start;
265 while (p < &__uml_help_end) {
266 printf("%s", *p);
267 p++;
268 }
269 exit(0);
270
271 return 0;
272}
273
274__uml_setup("--help", Usage,
275"--help\n"
276" Prints this message.\n\n"
277);
278
279static int __init uml_checksetup(char *line, int *add)
280{
281 struct uml_param *p;
282
283 p = &__uml_setup_start;
284 while(p < &__uml_setup_end) {
285 int n;
286
287 n = strlen(p->str);
288 if(!strncmp(line, p->str, n)){
289 if (p->setup_func(line + n, add)) return 1;
290 }
291 p++;
292 }
293 return 0;
294}
295
296static void __init uml_postsetup(void)
297{
298 initcall_t *p;
299
300 p = &__uml_postsetup_start;
301 while(p < &__uml_postsetup_end){
302 (*p)();
303 p++;
304 }
305 return;
306}
307
308/* Set during early boot */
309unsigned long brk_start;
310unsigned long end_iomem;
311EXPORT_SYMBOL(end_iomem);
312
313#define MIN_VMALLOC (32 * 1024 * 1024)
314
315int linux_main(int argc, char **argv)
316{
317 unsigned long avail, diff;
318 unsigned long virtmem_size, max_physmem;
319 unsigned int i, add;
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700320 char * mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 for (i = 1; i < argc; i++){
323 if((i == 1) && (argv[i][0] == ' ')) continue;
324 add = 1;
325 uml_checksetup(argv[i], &add);
326 if (add)
327 add_arg(argv[i]);
328 }
329 if(have_root == 0)
330 add_arg(DEFAULT_COMMAND_LINE);
331
Gennady Sharapov60d339f2005-09-03 15:57:47 -0700332 os_early_checks();
Paolo 'Blaisorblade' Giarrusso89236482005-09-30 11:59:00 -0700333 if (force_tt)
334 clear_can_do_skas();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 mode_tt = force_tt ? 1 : !can_do_skas();
336#ifndef CONFIG_MODE_TT
337 if (mode_tt) {
338 /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
339 * can_do_skas() returned 0, and the message is correct. */
340 printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
341 exit(1);
342 }
343#endif
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700344
345#ifndef CONFIG_MODE_SKAS
346 mode = "TT";
347#else
348 /* Show to the user the result of selection */
349 if (mode_tt)
350 mode = "TT";
351 else if (proc_mm && ptrace_faultinfo)
352 mode = "SKAS3";
353 else
354 mode = "SKAS0";
355#endif
356
357 printf("UML running in %s mode\n", mode);
358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
360 &host_task_size, &task_size);
361
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800362 /*
363 * Setting up handlers to 'sig_info' struct
364 */
365 os_fill_handlinfo(handlinfo_kern);
366
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 brk_start = (unsigned long) sbrk(0);
368 CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
369 /* Increase physical memory size for exec-shield users
370 so they actually get what they asked for. This should
371 add zero for non-exec shield users */
372
373 diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
374 if(diff > 1024 * 1024){
375 printf("Adding %ld bytes to physical memory to account for "
376 "exec-shield gap\n", diff);
377 physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
378 }
379
380 uml_physmem = uml_start;
381
382 /* Reserve up to 4M after the current brk */
383 uml_reserved = ROUND_4M(brk_start) + (1 << 22);
384
385 setup_machinename(system_utsname.machine);
386
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700387#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 argv1_begin = argv[1];
389 argv1_end = &argv[1][strlen(argv[1])];
390#endif
391
392 highmem = 0;
393 iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
394 max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
395
396 /* Zones have to begin on a 1 << MAX_ORDER page boundary,
397 * so this makes sure that's true for highmem
398 */
399 max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
400 if(physmem_size + iomem_size > max_physmem){
401 highmem = physmem_size + iomem_size - max_physmem;
402 physmem_size -= highmem;
403#ifndef CONFIG_HIGHMEM
404 highmem = 0;
405 printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
Jeff Dikeae173812005-11-07 00:58:57 -0800406 "to %lu bytes\n", physmem_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407#endif
408 }
409
410 high_physmem = uml_physmem + physmem_size;
411 end_iomem = high_physmem + iomem_size;
412 high_memory = (void *) end_iomem;
413
414 start_vm = VMALLOC_START;
415
416 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
417 if(init_maps(physmem_size, iomem_size, highmem)){
Jeff Dikeae173812005-11-07 00:58:57 -0800418 printf("Failed to allocate mem_map for %lu bytes of physical "
419 "memory and %lu bytes of highmem\n", physmem_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 highmem);
421 exit(1);
422 }
423
424 virtmem_size = physmem_size;
425 avail = get_kmem_end() - start_vm;
426 if(physmem_size > avail) virtmem_size = avail;
427 end_vm = start_vm + virtmem_size;
428
429 if(virtmem_size < physmem_size)
Jeff Dikeae173812005-11-07 00:58:57 -0800430 printf("Kernel virtual memory size shrunk to %lu bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 virtmem_size);
432
433 uml_postsetup();
434
435 task_protections((unsigned long) &init_thread_info);
436 os_flush_stdout();
437
438 return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
439}
440
441extern int uml_exitcode;
442
443static int panic_exit(struct notifier_block *self, unsigned long unused1,
444 void *unused2)
445{
446 bust_spinlocks(1);
447 show_regs(&(current->thread.regs));
448 bust_spinlocks(0);
449 uml_exitcode = 1;
450 machine_halt();
451 return(0);
452}
453
454static struct notifier_block panic_exit_notifier = {
455 .notifier_call = panic_exit,
456 .next = NULL,
457 .priority = 0
458};
459
460void __init setup_arch(char **cmdline_p)
461{
462 notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
463 paging_init();
Jeff Dike16c11162005-05-06 21:30:45 -0700464 strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 *cmdline_p = command_line;
466 setup_hostinfo();
467}
468
469void __init check_bugs(void)
470{
471 arch_check_bugs();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 check_sigio();
473 check_devanon();
474}
475
476void apply_alternatives(void *start, void *end)
477{
478}