blob: 4d10ec372a678a28124428f128d7b3b822b84d9f [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"
29#include "asm/setup.h"
30#include "user_util.h"
31#include "kern_util.h"
32#include "kern.h"
33#include "mem_user.h"
34#include "mem.h"
35#include "umid.h"
36#include "initrd.h"
37#include "init.h"
38#include "os.h"
39#include "choose-mode.h"
40#include "mode_kern.h"
41#include "mode.h"
42
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
107struct seq_operations cpuinfo_op = {
108 .start = c_start,
109 .next = c_next,
110 .stop = c_stop,
111 .show = show_cpuinfo,
112};
113
114pte_t * __bad_pagetable(void)
115{
116 panic("Someone should implement __bad_pagetable");
117 return(NULL);
118}
119
120/* Set in linux_main */
121unsigned long host_task_size;
122unsigned long task_size;
123
124unsigned long uml_start;
125
126/* Set in early boot */
127unsigned long uml_physmem;
128unsigned long uml_reserved;
129unsigned long start_vm;
130unsigned long end_vm;
131int ncpus = 1;
132
133#ifdef CONFIG_MODE_TT
134/* Pointer set in linux_main, the array itself is private to each thread,
135 * and changed at address space creation time so this poses no concurrency
136 * problems.
137 */
138static char *argv1_begin = NULL;
139static char *argv1_end = NULL;
140#endif
141
142/* Set in early boot */
143static int have_root __initdata = 0;
144long physmem_size = 32 * 1024 * 1024;
145
146void set_cmdline(char *cmd)
147{
148#ifdef CONFIG_MODE_TT
149 char *umid, *ptr;
150
151 if(CHOOSE_MODE(honeypot, 0)) return;
152
153 umid = get_umid(1);
154 if(umid != NULL){
155 snprintf(argv1_begin,
156 (argv1_end - argv1_begin) * sizeof(*ptr),
157 "(%s) ", umid);
158 ptr = &argv1_begin[strlen(argv1_begin)];
159 }
160 else ptr = argv1_begin;
161
162 snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
163 memset(argv1_begin + strlen(argv1_begin), '\0',
164 argv1_end - argv1_begin - strlen(argv1_begin));
165#endif
166}
167
168static char *usage_string =
169"User Mode Linux v%s\n"
170" available at http://user-mode-linux.sourceforge.net/\n\n";
171
172static int __init uml_version_setup(char *line, int *add)
173{
174 printf("%s\n", system_utsname.release);
175 exit(0);
176
177 return 0;
178}
179
180__uml_setup("--version", uml_version_setup,
181"--version\n"
182" Prints the version number of the kernel.\n\n"
183);
184
185static int __init uml_root_setup(char *line, int *add)
186{
187 have_root = 1;
188 return 0;
189}
190
191__uml_setup("root=", uml_root_setup,
192"root=<file containing the root fs>\n"
193" This is actually used by the generic kernel in exactly the same\n"
194" way as in any other kernel. If you configure a number of block\n"
195" devices and want to boot off something other than ubd0, you \n"
196" would use something like:\n"
197" root=/dev/ubd5\n\n"
198);
199
200#ifdef CONFIG_SMP
201static int __init uml_ncpus_setup(char *line, int *add)
202{
203 if (!sscanf(line, "%d", &ncpus)) {
204 printf("Couldn't parse [%s]\n", line);
205 return -1;
206 }
207
208 return 0;
209}
210
211__uml_setup("ncpus=", uml_ncpus_setup,
212"ncpus=<# of desired CPUs>\n"
213" This tells an SMP kernel how many virtual processors to start.\n\n"
214);
215#endif
216
217static int force_tt = 0;
218
219#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS)
220#define DEFAULT_TT 0
221
222static int __init mode_tt_setup(char *line, int *add)
223{
224 force_tt = 1;
225 return(0);
226}
227
228#else
229#ifdef CONFIG_MODE_SKAS
230
231#define DEFAULT_TT 0
232
233static int __init mode_tt_setup(char *line, int *add)
234{
235 printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
236 return(0);
237}
238
239#else
240#ifdef CONFIG_MODE_TT
241
242#define DEFAULT_TT 1
243
244static int __init mode_tt_setup(char *line, int *add)
245{
246 printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
247 return(0);
248}
249
250#else
251
252#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled
253
254#endif
255#endif
256#endif
257
258__uml_setup("mode=tt", mode_tt_setup,
259"mode=tt\n"
260" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n"
261" forces UML to run in tt (tracing thread) mode. It is not the default\n"
262" because it's slower and less secure than skas mode.\n\n"
263);
264
265int mode_tt = DEFAULT_TT;
266
267static int __init Usage(char *line, int *add)
268{
269 const char **p;
270
271 printf(usage_string, system_utsname.release);
272 p = &__uml_help_start;
273 while (p < &__uml_help_end) {
274 printf("%s", *p);
275 p++;
276 }
277 exit(0);
278
279 return 0;
280}
281
282__uml_setup("--help", Usage,
283"--help\n"
284" Prints this message.\n\n"
285);
286
287static int __init uml_checksetup(char *line, int *add)
288{
289 struct uml_param *p;
290
291 p = &__uml_setup_start;
292 while(p < &__uml_setup_end) {
293 int n;
294
295 n = strlen(p->str);
296 if(!strncmp(line, p->str, n)){
297 if (p->setup_func(line + n, add)) return 1;
298 }
299 p++;
300 }
301 return 0;
302}
303
304static void __init uml_postsetup(void)
305{
306 initcall_t *p;
307
308 p = &__uml_postsetup_start;
309 while(p < &__uml_postsetup_end){
310 (*p)();
311 p++;
312 }
313 return;
314}
315
316/* Set during early boot */
317unsigned long brk_start;
318unsigned long end_iomem;
319EXPORT_SYMBOL(end_iomem);
320
321#define MIN_VMALLOC (32 * 1024 * 1024)
322
323int linux_main(int argc, char **argv)
324{
325 unsigned long avail, diff;
326 unsigned long virtmem_size, max_physmem;
327 unsigned int i, add;
328
329 for (i = 1; i < argc; i++){
330 if((i == 1) && (argv[i][0] == ' ')) continue;
331 add = 1;
332 uml_checksetup(argv[i], &add);
333 if (add)
334 add_arg(argv[i]);
335 }
336 if(have_root == 0)
337 add_arg(DEFAULT_COMMAND_LINE);
338
339 mode_tt = force_tt ? 1 : !can_do_skas();
340#ifndef CONFIG_MODE_TT
341 if (mode_tt) {
342 /*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
343 * can_do_skas() returned 0, and the message is correct. */
344 printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n");
345 exit(1);
346 }
347#endif
348 uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
349 &host_task_size, &task_size);
350
351 /* Need to check this early because mmapping happens before the
352 * kernel is running.
353 */
354 check_tmpexec();
355
356 brk_start = (unsigned long) sbrk(0);
357 CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
358 /* Increase physical memory size for exec-shield users
359 so they actually get what they asked for. This should
360 add zero for non-exec shield users */
361
362 diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
363 if(diff > 1024 * 1024){
364 printf("Adding %ld bytes to physical memory to account for "
365 "exec-shield gap\n", diff);
366 physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
367 }
368
369 uml_physmem = uml_start;
370
371 /* Reserve up to 4M after the current brk */
372 uml_reserved = ROUND_4M(brk_start) + (1 << 22);
373
374 setup_machinename(system_utsname.machine);
375
376#ifdef CONFIG_MODE_TT
377 argv1_begin = argv[1];
378 argv1_end = &argv[1][strlen(argv[1])];
379#endif
380
381 highmem = 0;
382 iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
383 max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
384
385 /* Zones have to begin on a 1 << MAX_ORDER page boundary,
386 * so this makes sure that's true for highmem
387 */
388 max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
389 if(physmem_size + iomem_size > max_physmem){
390 highmem = physmem_size + iomem_size - max_physmem;
391 physmem_size -= highmem;
392#ifndef CONFIG_HIGHMEM
393 highmem = 0;
394 printf("CONFIG_HIGHMEM not enabled - physical memory shrunk "
395 "to %ld bytes\n", physmem_size);
396#endif
397 }
398
399 high_physmem = uml_physmem + physmem_size;
400 end_iomem = high_physmem + iomem_size;
401 high_memory = (void *) end_iomem;
402
403 start_vm = VMALLOC_START;
404
405 setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
406 if(init_maps(physmem_size, iomem_size, highmem)){
407 printf("Failed to allocate mem_map for %ld bytes of physical "
408 "memory and %ld bytes of highmem\n", physmem_size,
409 highmem);
410 exit(1);
411 }
412
413 virtmem_size = physmem_size;
414 avail = get_kmem_end() - start_vm;
415 if(physmem_size > avail) virtmem_size = avail;
416 end_vm = start_vm + virtmem_size;
417
418 if(virtmem_size < physmem_size)
419 printf("Kernel virtual memory size shrunk to %ld bytes\n",
420 virtmem_size);
421
422 uml_postsetup();
423
424 task_protections((unsigned long) &init_thread_info);
425 os_flush_stdout();
426
427 return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
428}
429
430extern int uml_exitcode;
431
432static int panic_exit(struct notifier_block *self, unsigned long unused1,
433 void *unused2)
434{
435 bust_spinlocks(1);
436 show_regs(&(current->thread.regs));
437 bust_spinlocks(0);
438 uml_exitcode = 1;
439 machine_halt();
440 return(0);
441}
442
443static struct notifier_block panic_exit_notifier = {
444 .notifier_call = panic_exit,
445 .next = NULL,
446 .priority = 0
447};
448
449void __init setup_arch(char **cmdline_p)
450{
451 notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
452 paging_init();
Jeff Dike16c11162005-05-06 21:30:45 -0700453 strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 *cmdline_p = command_line;
455 setup_hostinfo();
456}
457
458void __init check_bugs(void)
459{
460 arch_check_bugs();
461 check_ptrace();
462 check_sigio();
463 check_devanon();
464}
465
466void apply_alternatives(void *start, void *end)
467{
468}