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