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