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