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