blob: 668eba2d2e8352cb35caaaaeed8b6c7cb306c8ee [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"
20#include "asm/page.h"
21#include "asm/pgtable.h"
22#include "asm/ptrace.h"
23#include "asm/elf.h"
24#include "asm/user.h"
Jeff Dike16c11162005-05-06 21:30:45 -070025#include "asm/setup.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include "ubd_user.h"
27#include "asm/current.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include "user_util.h"
29#include "kern_util.h"
30#include "kern.h"
31#include "mem_user.h"
32#include "mem.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include "initrd.h"
34#include "init.h"
35#include "os.h"
36#include "choose-mode.h"
37#include "mode_kern.h"
38#include "mode.h"
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -070039#ifdef UML_CONFIG_MODE_SKAS
40#include "skas.h"
41#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#define DEFAULT_COMMAND_LINE "root=98:0"
44
45/* Changed in linux_main and setup_arch, which run before SMP is started */
Jeff Dike16c11162005-05-06 21:30:45 -070046static char command_line[COMMAND_LINE_SIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
Jeff Dike16c11162005-05-06 21:30:45 -070048static void add_arg(char *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070049{
50 if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
51 printf("add_arg: Too many command line arguments!\n");
52 exit(1);
53 }
54 if(strlen(command_line) > 0)
55 strcat(command_line, " ");
56 strcat(command_line, arg);
57}
58
59struct cpuinfo_um boot_cpu_data = {
60 .loops_per_jiffy = 0,
61 .ipi_pipe = { -1, -1 }
62};
63
64unsigned long thread_saved_pc(struct task_struct *task)
65{
66 return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
67 task)));
68}
69
70static int show_cpuinfo(struct seq_file *m, void *v)
71{
72 int index = 0;
73
74#ifdef CONFIG_SMP
75 index = (struct cpuinfo_um *) v - cpu_data;
76 if (!cpu_online(index))
77 return 0;
78#endif
79
80 seq_printf(m, "processor\t: %d\n", index);
81 seq_printf(m, "vendor_id\t: User Mode Linux\n");
82 seq_printf(m, "model name\t: UML\n");
83 seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
84 seq_printf(m, "host\t\t: %s\n", host_info);
85 seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
86 loops_per_jiffy/(500000/HZ),
87 (loops_per_jiffy/(5000/HZ)) % 100);
88
89 return(0);
90}
91
92static void *c_start(struct seq_file *m, loff_t *pos)
93{
94 return *pos < NR_CPUS ? cpu_data + *pos : NULL;
95}
96
97static void *c_next(struct seq_file *m, void *v, loff_t *pos)
98{
99 ++*pos;
100 return c_start(m, pos);
101}
102
103static void c_stop(struct seq_file *m, void *v)
104{
105}
106
Jeff Dike5e7672e2006-09-27 01:50:33 -0700107const struct seq_operations cpuinfo_op = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 .start = c_start,
109 .next = c_next,
110 .stop = c_stop,
111 .show = show_cpuinfo,
112};
113
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114/* Set in linux_main */
115unsigned long host_task_size;
116unsigned long task_size;
117
118unsigned long uml_start;
119
120/* Set in early boot */
121unsigned long uml_physmem;
122unsigned long uml_reserved;
123unsigned long start_vm;
124unsigned long end_vm;
125int ncpus = 1;
126
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700127#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128/* Pointer set in linux_main, the array itself is private to each thread,
129 * and changed at address space creation time so this poses no concurrency
130 * problems.
131 */
132static char *argv1_begin = NULL;
133static char *argv1_end = NULL;
134#endif
135
136/* Set in early boot */
137static int have_root __initdata = 0;
Jeff Dikeae173812005-11-07 00:58:57 -0800138long long physmem_size = 32 * 1024 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140void set_cmdline(char *cmd)
141{
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700142#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 char *umid, *ptr;
144
145 if(CHOOSE_MODE(honeypot, 0)) return;
146
Jeff Dike7eebe8a2006-01-06 00:19:01 -0800147 umid = get_umid();
148 if(*umid != '\0'){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 snprintf(argv1_begin,
150 (argv1_end - argv1_begin) * sizeof(*ptr),
151 "(%s) ", umid);
152 ptr = &argv1_begin[strlen(argv1_begin)];
153 }
154 else ptr = argv1_begin;
155
156 snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
157 memset(argv1_begin + strlen(argv1_begin), '\0',
158 argv1_end - argv1_begin - strlen(argv1_begin));
159#endif
160}
161
162static char *usage_string =
163"User Mode Linux v%s\n"
164" available at http://user-mode-linux.sourceforge.net/\n\n";
165
166static int __init uml_version_setup(char *line, int *add)
167{
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700168 printf("%s\n", init_utsname()->release);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 exit(0);
170
171 return 0;
172}
173
174__uml_setup("--version", uml_version_setup,
175"--version\n"
176" Prints the version number of the kernel.\n\n"
177);
178
179static int __init uml_root_setup(char *line, int *add)
180{
181 have_root = 1;
182 return 0;
183}
184
185__uml_setup("root=", uml_root_setup,
186"root=<file containing the root fs>\n"
187" This is actually used by the generic kernel in exactly the same\n"
188" way as in any other kernel. If you configure a number of block\n"
189" devices and want to boot off something other than ubd0, you \n"
190" would use something like:\n"
191" root=/dev/ubd5\n\n"
192);
193
Jeff Dikefbd55772006-02-07 12:58:40 -0800194#ifndef CONFIG_MODE_TT
195
196static int __init no_skas_debug_setup(char *line, int *add)
197{
198 printf("'debug' is not necessary to gdb UML in skas mode - run \n");
199 printf("'gdb linux' and disable CONFIG_CMDLINE_ON_HOST if gdb \n");
200 printf("doesn't work as expected\n");
201
202 return 0;
203}
204
205__uml_setup("debug", no_skas_debug_setup,
206"debug\n"
207" this flag is not needed to run gdb on UML in skas mode\n\n"
208);
209
210#endif
211
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212#ifdef CONFIG_SMP
213static int __init uml_ncpus_setup(char *line, int *add)
214{
215 if (!sscanf(line, "%d", &ncpus)) {
216 printf("Couldn't parse [%s]\n", line);
217 return -1;
218 }
219
220 return 0;
221}
222
223__uml_setup("ncpus=", uml_ncpus_setup,
224"ncpus=<# of desired CPUs>\n"
225" This tells an SMP kernel how many virtual processors to start.\n\n"
226);
227#endif
228
229static int force_tt = 0;
230
231#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
232#define DEFAULT_TT 0
233
234static int __init mode_tt_setup(char *line, int *add)
235{
236 force_tt = 1;
237 return(0);
238}
239
240#else
241#ifdef CONFIG_MODE_SKAS
242
243#define DEFAULT_TT 0
244
245static int __init mode_tt_setup(char *line, int *add)
246{
247 printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
248 return(0);
249}
250
251#else
252#ifdef CONFIG_MODE_TT
253
254#define DEFAULT_TT 1
255
256static int __init mode_tt_setup(char *line, int *add)
257{
258 printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
259 return(0);
260}
261
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262#endif
263#endif
264#endif
265
266__uml_setup("mode=tt", mode_tt_setup,
267"mode=tt\n"
268" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
269" forces UML to run in tt (tracing thread) mode. It is not the default\n"
270" because it's slower and less secure than skas mode.\n\n"
271);
272
273int mode_tt = DEFAULT_TT;
274
275static int __init Usage(char *line, int *add)
276{
277 const char **p;
278
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700279 printf(usage_string, init_utsname()->release);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 p = &__uml_help_start;
281 while (p < &__uml_help_end) {
282 printf("%s", *p);
283 p++;
284 }
285 exit(0);
286
287 return 0;
288}
289
290__uml_setup("--help", Usage,
291"--help\n"
292" Prints this message.\n\n"
293);
294
295static int __init uml_checksetup(char *line, int *add)
296{
297 struct uml_param *p;
298
299 p = &__uml_setup_start;
300 while(p < &__uml_setup_end) {
301 int n;
302
303 n = strlen(p->str);
304 if(!strncmp(line, p->str, n)){
305 if (p->setup_func(line + n, add)) return 1;
306 }
307 p++;
308 }
309 return 0;
310}
311
312static void __init uml_postsetup(void)
313{
314 initcall_t *p;
315
316 p = &__uml_postsetup_start;
317 while(p < &__uml_postsetup_end){
318 (*p)();
319 p++;
320 }
321 return;
322}
323
324/* Set during early boot */
325unsigned long brk_start;
326unsigned long end_iomem;
327EXPORT_SYMBOL(end_iomem);
328
329#define MIN_VMALLOC (32 * 1024 * 1024)
330
Jeff Dike23bbd582006-07-10 04:45:06 -0700331extern char __binary_start;
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333int linux_main(int argc, char **argv)
334{
335 unsigned long avail, diff;
336 unsigned long virtmem_size, max_physmem;
337 unsigned int i, add;
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700338 char * mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
340 for (i = 1; i < argc; i++){
341 if((i == 1) && (argv[i][0] == ' ')) continue;
342 add = 1;
343 uml_checksetup(argv[i], &add);
344 if (add)
345 add_arg(argv[i]);
346 }
347 if(have_root == 0)
348 add_arg(DEFAULT_COMMAND_LINE);
349
Gennady Sharapov60d339f2005-09-03 15:57:47 -0700350 os_early_checks();
Paolo 'Blaisorblade' Giarrusso89236482005-09-30 11:59:00 -0700351 if (force_tt)
352 clear_can_do_skas();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 mode_tt = force_tt ? 1 : !can_do_skas();
354#ifndef CONFIG_MODE_TT
355 if (mode_tt) {
356 /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
357 * can_do_skas() returned 0, and the message is correct. */
358 printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
359 exit(1);
360 }
361#endif
Paolo 'Blaisorblade' Giarrussocb665042005-07-27 11:43:31 -0700362
363#ifndef CONFIG_MODE_SKAS
364 mode = "TT";
365#else
366 /* Show to the user the result of selection */
367 if (mode_tt)
368 mode = "TT";
369 else if (proc_mm && ptrace_faultinfo)
370 mode = "SKAS3";
371 else
372 mode = "SKAS0";
373#endif
374
375 printf("UML running in %s mode\n", mode);
376
Jeff Dike23bbd582006-07-10 04:45:06 -0700377 uml_start = (unsigned long) &__binary_start;
378 host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt,
379 set_task_sizes_skas, &task_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -0800381 /*
382 * Setting up handlers to 'sig_info' struct
383 */
384 os_fill_handlinfo(handlinfo_kern);
385
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 brk_start = (unsigned long) sbrk(0);
387 CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
388 /* Increase physical memory size for exec-shield users
389 so they actually get what they asked for. This should
390 add zero for non-exec shield users */
391
392 diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
393 if(diff > 1024 * 1024){
394 printf("Adding %ld bytes to physical memory to account for "
395 "exec-shield gap\n", diff);
396 physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
397 }
398
Jeff Dike23bbd582006-07-10 04:45:06 -0700399 uml_physmem = uml_start & PAGE_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
401 /* Reserve up to 4M after the current brk */
402 uml_reserved = ROUND_4M(brk_start) + (1 << 22);
403
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700404 setup_machinename(init_utsname()->machine);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Paolo 'Blaisorblade' Giarrusso02215752005-09-03 15:57:23 -0700406#ifdef CONFIG_CMDLINE_ON_HOST
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 argv1_begin = argv[1];
408 argv1_end = &argv[1][strlen(argv[1])];
409#endif
410
411 highmem = 0;
412 iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
413 max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
414
415 /* Zones have to begin on a 1 << MAX_ORDER page boundary,
416 * so this makes sure that's true for highmem
417 */
418 max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
419 if(physmem_size + iomem_size > max_physmem){
420 highmem = physmem_size + iomem_size - max_physmem;
421 physmem_size -= highmem;
422#ifndef CONFIG_HIGHMEM
423 highmem = 0;
424 printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
Jeff Diked9f8b622006-03-27 01:14:29 -0800425 "to %Lu bytes\n", physmem_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426#endif
427 }
428
429 high_physmem = uml_physmem + physmem_size;
430 end_iomem = high_physmem + iomem_size;
431 high_memory = (void *) end_iomem;
432
433 start_vm = VMALLOC_START;
434
435 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
436 if(init_maps(physmem_size, iomem_size, highmem)){
Jeff Diked9f8b622006-03-27 01:14:29 -0800437 printf("Failed to allocate mem_map for %Lu bytes of physical "
438 "memory and %Lu bytes of highmem\n", physmem_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 highmem);
440 exit(1);
441 }
442
443 virtmem_size = physmem_size;
444 avail = get_kmem_end() - start_vm;
445 if(physmem_size > avail) virtmem_size = avail;
446 end_vm = start_vm + virtmem_size;
447
448 if(virtmem_size < physmem_size)
Jeff Dikeae173812005-11-07 00:58:57 -0800449 printf("Kernel virtual memory size shrunk to %lu bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 virtmem_size);
451
452 uml_postsetup();
453
454 task_protections((unsigned long) &init_thread_info);
455 os_flush_stdout();
456
457 return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
458}
459
460extern int uml_exitcode;
461
462static int panic_exit(struct notifier_block *self, unsigned long unused1,
463 void *unused2)
464{
465 bust_spinlocks(1);
466 show_regs(&(current->thread.regs));
467 bust_spinlocks(0);
468 uml_exitcode = 1;
469 machine_halt();
470 return(0);
471}
472
473static struct notifier_block panic_exit_notifier = {
474 .notifier_call = panic_exit,
475 .next = NULL,
476 .priority = 0
477};
478
479void __init setup_arch(char **cmdline_p)
480{
Alan Sterne041c682006-03-27 01:16:30 -0800481 atomic_notifier_chain_register(&panic_notifier_list,
482 &panic_exit_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 paging_init();
Alon Bar-Lev19bf7e72007-02-12 00:54:23 -0800484 strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 *cmdline_p = command_line;
486 setup_hostinfo();
487}
488
489void __init check_bugs(void)
490{
491 arch_check_bugs();
Jeff Dike8e367062006-03-27 01:14:32 -0800492 os_check_bugs();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493}
494
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800495void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
496{
497}
498
Theodore Tsoc61a8412006-07-03 00:24:09 -0700499#ifdef CONFIG_SMP
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800500void alternatives_smp_module_add(struct module *mod, char *name,
501 void *locks, void *locks_end,
502 void *text, void *text_end)
503{
504}
505
506void alternatives_smp_module_del(struct module *mod)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507{
508}
Theodore Tsoc61a8412006-07-03 00:24:09 -0700509#endif