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