blob: 09f6f7ce4695f73c10a1507acfb122b854cf2fe5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * 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;
140long physmem_size = 32 * 1024 * 1024;
141
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
149 umid = get_umid(1);
150 if(umid != NULL){
151 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
246#else
247
248#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled
249
250#endif
251#endif
252#endif
253
254__uml_setup("mode=tt", mode_tt_setup,
255"mode=tt\n"
256" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
257" forces UML to run in tt (tracing thread) mode. It is not the default\n"
258" because it's slower and less secure than skas mode.\n\n"
259);
260
261int mode_tt = DEFAULT_TT;
262
263static int __init Usage(char *line, int *add)
264{
265 const char **p;
266
267 printf(usage_string, system_utsname.release);
268 p = &__uml_help_start;
269 while (p < &__uml_help_end) {
270 printf("%s", *p);
271 p++;
272 }
273 exit(0);
274
275 return 0;
276}
277
278__uml_setup("--help", Usage,
279"--help\n"
280" Prints this message.\n\n"
281);
282
283static int __init uml_checksetup(char *line, int *add)
284{
285 struct uml_param *p;
286
287 p = &__uml_setup_start;
288 while(p < &__uml_setup_end) {
289 int n;
290
291 n = strlen(p->str);
292 if(!strncmp(line, p->str, n)){
293 if (p->setup_func(line + n, add)) return 1;
294 }
295 p++;
296 }
297 return 0;
298}
299
300static void __init uml_postsetup(void)
301{
302 initcall_t *p;
303
304 p = &__uml_postsetup_start;
305 while(p < &__uml_postsetup_end){
306 (*p)();
307 p++;
308 }
309 return;
310}
311
312/* Set during early boot */
313unsigned long brk_start;
314unsigned long end_iomem;
315EXPORT_SYMBOL(end_iomem);
316
317#define MIN_VMALLOC (32 * 1024 * 1024)
318
319int linux_main(int argc, char **argv)
320{
321 unsigned long avail, diff;
322 unsigned long virtmem_size, max_physmem;
323 unsigned int i, add;
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700324 char * mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 for (i = 1; i < argc; i++){
327 if((i == 1) && (argv[i][0] == ' ')) continue;
328 add = 1;
329 uml_checksetup(argv[i], &add);
330 if (add)
331 add_arg(argv[i]);
332 }
333 if(have_root == 0)
334 add_arg(DEFAULT_COMMAND_LINE);
335
Gennady Sharapov60d339f2005-09-03 15:57:47 -0700336 os_early_checks();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 mode_tt = force_tt ? 1 : !can_do_skas();
338#ifndef CONFIG_MODE_TT
339 if (mode_tt) {
340 /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
341 * can_do_skas() returned 0, and the message is correct. */
342 printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
343 exit(1);
344 }
345#endif
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700346
347#ifndef CONFIG_MODE_SKAS
348 mode = "TT";
349#else
350 /* Show to the user the result of selection */
351 if (mode_tt)
352 mode = "TT";
353 else if (proc_mm && ptrace_faultinfo)
354 mode = "SKAS3";
355 else
356 mode = "SKAS0";
357#endif
358
359 printf("UML running in %s mode\n", mode);
360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
362 &host_task_size, &task_size);
363
364 /* Need to check this early because mmapping happens before the
365 * kernel is running.
366 */
367 check_tmpexec();
368
369 brk_start = (unsigned long) sbrk(0);
370 CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
371 /* Increase physical memory size for exec-shield users
372 so they actually get what they asked for. This should
373 add zero for non-exec shield users */
374
375 diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
376 if(diff > 1024 * 1024){
377 printf("Adding %ld bytes to physical memory to account for "
378 "exec-shield gap\n", diff);
379 physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
380 }
381
382 uml_physmem = uml_start;
383
384 /* Reserve up to 4M after the current brk */
385 uml_reserved = ROUND_4M(brk_start) + (1 << 22);
386
387 setup_machinename(system_utsname.machine);
388
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700389#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 argv1_begin = argv[1];
391 argv1_end = &argv[1][strlen(argv[1])];
392#endif
393
394 highmem = 0;
395 iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
396 max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
397
398 /* Zones have to begin on a 1 << MAX_ORDER page boundary,
399 * so this makes sure that's true for highmem
400 */
401 max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
402 if(physmem_size + iomem_size > max_physmem){
403 highmem = physmem_size + iomem_size - max_physmem;
404 physmem_size -= highmem;
405#ifndef CONFIG_HIGHMEM
406 highmem = 0;
407 printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
408 "to %ld bytes\n", physmem_size);
409#endif
410 }
411
412 high_physmem = uml_physmem + physmem_size;
413 end_iomem = high_physmem + iomem_size;
414 high_memory = (void *) end_iomem;
415
416 start_vm = VMALLOC_START;
417
418 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
419 if(init_maps(physmem_size, iomem_size, highmem)){
420 printf("Failed to allocate mem_map for %ld bytes of physical "
421 "memory and %ld bytes of highmem\n", physmem_size,
422 highmem);
423 exit(1);
424 }
425
426 virtmem_size = physmem_size;
427 avail = get_kmem_end() - start_vm;
428 if(physmem_size > avail) virtmem_size = avail;
429 end_vm = start_vm + virtmem_size;
430
431 if(virtmem_size < physmem_size)
432 printf("Kernel virtual memory size shrunk to %ld bytes\n",
433 virtmem_size);
434
435 uml_postsetup();
436
437 task_protections((unsigned long) &init_thread_info);
438 os_flush_stdout();
439
440 return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
441}
442
443extern int uml_exitcode;
444
445static int panic_exit(struct notifier_block *self, unsigned long unused1,
446 void *unused2)
447{
448 bust_spinlocks(1);
449 show_regs(&(current->thread.regs));
450 bust_spinlocks(0);
451 uml_exitcode = 1;
452 machine_halt();
453 return(0);
454}
455
456static struct notifier_block panic_exit_notifier = {
457 .notifier_call = panic_exit,
458 .next = NULL,
459 .priority = 0
460};
461
462void __init setup_arch(char **cmdline_p)
463{
464 notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
465 paging_init();
Jeff Dike16c11162005-05-06 21:30:45 -0700466 strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 *cmdline_p = command_line;
468 setup_hostinfo();
469}
470
471void __init check_bugs(void)
472{
473 arch_check_bugs();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 check_sigio();
475 check_devanon();
476}
477
478void apply_alternatives(void *start, void *end)
479{
480}