Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4 : */
5 :
6 : #include <linux/delay.h>
7 : #include <linux/init.h>
8 : #include <linux/mm.h>
9 : #include <linux/ctype.h>
10 : #include <linux/module.h>
11 : #include <linux/panic_notifier.h>
12 : #include <linux/seq_file.h>
13 : #include <linux/string.h>
14 : #include <linux/utsname.h>
15 : #include <linux/sched.h>
16 : #include <linux/sched/task.h>
17 : #include <linux/kmsg_dump.h>
18 : #include <linux/suspend.h>
19 :
20 : #include <asm/processor.h>
21 : #include <asm/cpufeature.h>
22 : #include <asm/sections.h>
23 : #include <asm/setup.h>
24 : #include <as-layout.h>
25 : #include <arch.h>
26 : #include <init.h>
27 : #include <kern.h>
28 : #include <kern_util.h>
29 : #include <mem_user.h>
30 : #include <os.h>
31 :
32 : #include "um_arch.h"
33 :
34 : #define DEFAULT_COMMAND_LINE_ROOT "root=98:0"
35 : #define DEFAULT_COMMAND_LINE_CONSOLE "console=tty"
36 :
37 : /* Changed in add_arg and setup_arch, which run before SMP is started */
38 : static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
39 :
40 20 : static void __init add_arg(char *arg)
41 : {
42 20 : if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
43 0 : os_warn("add_arg: Too many command line arguments!\n");
44 0 : exit(1);
45 : }
46 20 : if (strlen(command_line) > 0)
47 15 : strcat(command_line, " ");
48 20 : strcat(command_line, arg);
49 20 : }
50 :
51 : /*
52 : * These fields are initialized at boot time and not changed.
53 : * XXX This structure is used only in the non-SMP case. Maybe this
54 : * should be moved to smp.c.
55 : */
56 : struct cpuinfo_um boot_cpu_data = {
57 : .loops_per_jiffy = 0,
58 : .ipi_pipe = { -1, -1 },
59 : .cache_alignment = L1_CACHE_BYTES,
60 : .x86_capability = { 0 }
61 : };
62 :
63 : EXPORT_SYMBOL(boot_cpu_data);
64 :
65 : union thread_union cpu0_irqstack
66 : __section(".data..init_irqstack") =
67 : { .thread_info = INIT_THREAD_INFO(init_task) };
68 :
69 : /* Changed in setup_arch, which is called in early boot */
70 : static char host_info[(__NEW_UTS_LEN + 1) * 5];
71 :
72 0 : static int show_cpuinfo(struct seq_file *m, void *v)
73 : {
74 0 : int i = 0;
75 :
76 0 : seq_printf(m, "processor\t: %d\n", i);
77 0 : seq_printf(m, "vendor_id\t: User Mode Linux\n");
78 0 : seq_printf(m, "model name\t: UML\n");
79 0 : seq_printf(m, "mode\t\t: skas\n");
80 0 : seq_printf(m, "host\t\t: %s\n", host_info);
81 0 : seq_printf(m, "fpu\t\t: %s\n", cpu_has(&boot_cpu_data, X86_FEATURE_FPU) ? "yes" : "no");
82 0 : seq_printf(m, "flags\t\t:");
83 0 : for (i = 0; i < 32*NCAPINTS; i++)
84 0 : if (cpu_has(&boot_cpu_data, i) && (x86_cap_flags[i] != NULL))
85 0 : seq_printf(m, " %s", x86_cap_flags[i]);
86 0 : seq_printf(m, "\n");
87 0 : seq_printf(m, "cache_alignment\t: %d\n", boot_cpu_data.cache_alignment);
88 0 : seq_printf(m, "bogomips\t: %lu.%02lu\n",
89 : loops_per_jiffy/(500000/HZ),
90 0 : (loops_per_jiffy/(5000/HZ)) % 100);
91 :
92 :
93 0 : return 0;
94 : }
95 :
96 0 : static void *c_start(struct seq_file *m, loff_t *pos)
97 : {
98 0 : return *pos < NR_CPUS ? cpu_data + *pos : NULL;
99 : }
100 :
101 0 : static void *c_next(struct seq_file *m, void *v, loff_t *pos)
102 : {
103 0 : ++*pos;
104 0 : return c_start(m, pos);
105 : }
106 :
107 0 : static void c_stop(struct seq_file *m, void *v)
108 : {
109 0 : }
110 :
111 : const struct seq_operations cpuinfo_op = {
112 : .start = c_start,
113 : .next = c_next,
114 : .stop = c_stop,
115 : .show = show_cpuinfo,
116 : };
117 :
118 : /* Set in linux_main */
119 : unsigned long uml_physmem;
120 : EXPORT_SYMBOL(uml_physmem);
121 :
122 : unsigned long uml_reserved; /* Also modified in mem_init */
123 : unsigned long start_vm;
124 : unsigned long end_vm;
125 :
126 : /* Set in uml_ncpus_setup */
127 : int ncpus = 1;
128 :
129 : /* Set in early boot */
130 : static int have_root __initdata;
131 : static int have_console __initdata;
132 :
133 : /* Set in uml_mem_setup and modified in linux_main */
134 : long long physmem_size = 32 * 1024 * 1024;
135 : EXPORT_SYMBOL(physmem_size);
136 :
137 : static const char *usage_string =
138 : "User Mode Linux v%s\n"
139 : " available at http://user-mode-linux.sourceforge.net/\n\n";
140 :
141 0 : static int __init uml_version_setup(char *line, int *add)
142 : {
143 : /* Explicitly use printf() to show version in stdout */
144 0 : printf("%s\n", init_utsname()->release);
145 0 : exit(0);
146 :
147 0 : return 0;
148 : }
149 :
150 : __uml_setup("--version", uml_version_setup,
151 : "--version\n"
152 : " Prints the version number of the kernel.\n\n"
153 : );
154 :
155 0 : static int __init uml_root_setup(char *line, int *add)
156 : {
157 0 : have_root = 1;
158 0 : return 0;
159 : }
160 :
161 : __uml_setup("root=", uml_root_setup,
162 : "root=<file containing the root fs>\n"
163 : " This is actually used by the generic kernel in exactly the same\n"
164 : " way as in any other kernel. If you configure a number of block\n"
165 : " devices and want to boot off something other than ubd0, you \n"
166 : " would use something like:\n"
167 : " root=/dev/ubd5\n\n"
168 : );
169 :
170 0 : static int __init no_skas_debug_setup(char *line, int *add)
171 : {
172 0 : os_warn("'debug' is not necessary to gdb UML in skas mode - run\n");
173 0 : os_warn("'gdb linux'\n");
174 :
175 0 : return 0;
176 : }
177 :
178 : __uml_setup("debug", no_skas_debug_setup,
179 : "debug\n"
180 : " this flag is not needed to run gdb on UML in skas mode\n\n"
181 : );
182 :
183 5 : static int __init uml_console_setup(char *line, int *add)
184 : {
185 5 : have_console = 1;
186 5 : return 0;
187 : }
188 :
189 : __uml_setup("console=", uml_console_setup,
190 : "console=<preferred console>\n"
191 : " Specify the preferred console output driver\n\n"
192 : );
193 :
194 0 : static int __init Usage(char *line, int *add)
195 : {
196 : const char **p;
197 :
198 0 : printf(usage_string, init_utsname()->release);
199 0 : p = &__uml_help_start;
200 : /* Explicitly use printf() to show help in stdout */
201 0 : while (p < &__uml_help_end) {
202 0 : printf("%s", *p);
203 0 : p++;
204 : }
205 0 : exit(0);
206 0 : return 0;
207 : }
208 :
209 : __uml_setup("--help", Usage,
210 : "--help\n"
211 : " Prints this message.\n\n"
212 : );
213 :
214 15 : static void __init uml_checksetup(char *line, int *add)
215 : {
216 : struct uml_param *p;
217 :
218 15 : p = &__uml_setup_start;
219 210 : while (p < &__uml_setup_end) {
220 : size_t n;
221 :
222 180 : n = strlen(p->str);
223 180 : if (!strncmp(line, p->str, n) && p->setup_func(line + n, add))
224 : return;
225 180 : p++;
226 : }
227 : }
228 :
229 1 : static void __init uml_postsetup(void)
230 : {
231 : initcall_t *p;
232 :
233 1 : p = &__uml_postsetup_start;
234 3 : while (p < &__uml_postsetup_end) {
235 1 : (*p)();
236 1 : p++;
237 : }
238 1 : return;
239 : }
240 :
241 0 : static int panic_exit(struct notifier_block *self, unsigned long unused1,
242 : void *unused2)
243 : {
244 0 : kmsg_dump(KMSG_DUMP_PANIC);
245 0 : bust_spinlocks(1);
246 0 : bust_spinlocks(0);
247 0 : uml_exitcode = 1;
248 0 : os_dump_core();
249 : return 0;
250 : }
251 :
252 : static struct notifier_block panic_exit_notifier = {
253 : .notifier_call = panic_exit,
254 : .next = NULL,
255 : .priority = 0
256 : };
257 :
258 1 : void uml_finishsetup(void)
259 : {
260 1 : atomic_notifier_chain_register(&panic_notifier_list,
261 : &panic_exit_notifier);
262 :
263 1 : uml_postsetup();
264 :
265 1 : new_thread_handler();
266 0 : }
267 :
268 : /* Set during early boot */
269 : unsigned long stub_start;
270 : unsigned long task_size;
271 : EXPORT_SYMBOL(task_size);
272 :
273 : unsigned long host_task_size;
274 :
275 : unsigned long brk_start;
276 : unsigned long end_iomem;
277 : EXPORT_SYMBOL(end_iomem);
278 :
279 : #define MIN_VMALLOC (32 * 1024 * 1024)
280 :
281 2 : static void parse_host_cpu_flags(char *line)
282 : {
283 : int i;
284 1282 : for (i = 0; i < 32*NCAPINTS; i++) {
285 1280 : if ((x86_cap_flags[i] != NULL) && strstr(line, x86_cap_flags[i]))
286 134 : set_cpu_cap(&boot_cpu_data, i);
287 : }
288 2 : }
289 0 : static void parse_cache_line(char *line)
290 : {
291 : long res;
292 0 : char *to_parse = strstr(line, ":");
293 0 : if (to_parse) {
294 0 : to_parse++;
295 0 : while (*to_parse != 0 && isspace(*to_parse)) {
296 0 : to_parse++;
297 : }
298 0 : if (kstrtoul(to_parse, 10, &res) == 0 && is_power_of_2(res))
299 0 : boot_cpu_data.cache_alignment = res;
300 : else
301 0 : boot_cpu_data.cache_alignment = L1_CACHE_BYTES;
302 : }
303 0 : }
304 :
305 5 : int __init linux_main(int argc, char **argv)
306 : {
307 : unsigned long avail, diff;
308 : unsigned long virtmem_size, max_physmem;
309 : unsigned long stack;
310 : unsigned int i;
311 : int add;
312 :
313 20 : for (i = 1; i < argc; i++) {
314 15 : if ((i == 1) && (argv[i][0] == ' '))
315 0 : continue;
316 15 : add = 1;
317 15 : uml_checksetup(argv[i], &add);
318 15 : if (add)
319 15 : add_arg(argv[i]);
320 : }
321 5 : if (have_root == 0)
322 5 : add_arg(DEFAULT_COMMAND_LINE_ROOT);
323 :
324 5 : if (have_console == 0)
325 0 : add_arg(DEFAULT_COMMAND_LINE_CONSOLE);
326 :
327 5 : host_task_size = os_get_top_address();
328 : /* reserve two pages for the stubs */
329 5 : host_task_size -= 2 * PAGE_SIZE;
330 5 : stub_start = host_task_size;
331 :
332 : /*
333 : * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps
334 : * out
335 : */
336 5 : task_size = host_task_size & PGDIR_MASK;
337 :
338 : /* OS sanity checks that need to happen before the kernel runs */
339 5 : os_early_checks();
340 :
341 1 : get_host_cpu_features(parse_host_cpu_flags, parse_cache_line);
342 :
343 1 : brk_start = (unsigned long) sbrk(0);
344 :
345 : /*
346 : * Increase physical memory size for exec-shield users
347 : * so they actually get what they asked for. This should
348 : * add zero for non-exec shield users
349 : */
350 :
351 1 : diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
352 1 : if (diff > 1024 * 1024) {
353 1 : os_info("Adding %ld bytes to physical memory to account for "
354 : "exec-shield gap\n", diff);
355 1 : physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
356 : }
357 :
358 1 : uml_physmem = (unsigned long) __binary_start & PAGE_MASK;
359 :
360 : /* Reserve up to 4M after the current brk */
361 1 : uml_reserved = ROUND_4M(brk_start) + (1 << 22);
362 :
363 1 : setup_machinename(init_utsname()->machine);
364 :
365 1 : highmem = 0;
366 1 : iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
367 1 : max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC;
368 :
369 : /*
370 : * Zones have to begin on a 1 << MAX_ORDER page boundary,
371 : * so this makes sure that's true for highmem
372 : */
373 1 : max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
374 1 : if (physmem_size + iomem_size > max_physmem) {
375 0 : highmem = physmem_size + iomem_size - max_physmem;
376 0 : physmem_size -= highmem;
377 : }
378 :
379 1 : high_physmem = uml_physmem + physmem_size;
380 1 : end_iomem = high_physmem + iomem_size;
381 1 : high_memory = (void *) end_iomem;
382 :
383 1 : start_vm = VMALLOC_START;
384 :
385 1 : virtmem_size = physmem_size;
386 1 : stack = (unsigned long) argv;
387 1 : stack &= ~(1024 * 1024 - 1);
388 1 : avail = stack - start_vm;
389 1 : if (physmem_size > avail)
390 0 : virtmem_size = avail;
391 1 : end_vm = start_vm + virtmem_size;
392 :
393 1 : if (virtmem_size < physmem_size)
394 0 : os_info("Kernel virtual memory size shrunk to %lu bytes\n",
395 : virtmem_size);
396 :
397 1 : os_flush_stdout();
398 :
399 1 : return start_uml();
400 : }
401 :
402 1 : int __init __weak read_initrd(void)
403 : {
404 1 : return 0;
405 : }
406 :
407 1 : void __init setup_arch(char **cmdline_p)
408 : {
409 1 : stack_protections((unsigned long) &init_thread_info);
410 1 : setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
411 1 : mem_total_pages(physmem_size, iomem_size, highmem);
412 : uml_dtb_init();
413 1 : read_initrd();
414 :
415 1 : paging_init();
416 1 : strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
417 1 : *cmdline_p = command_line;
418 1 : setup_hostinfo(host_info, sizeof host_info);
419 1 : }
420 :
421 1 : void __init check_bugs(void)
422 : {
423 1 : arch_check_bugs();
424 1 : os_check_bugs();
425 1 : }
426 :
427 0 : void apply_ibt_endbr(s32 *start, s32 *end)
428 : {
429 0 : }
430 :
431 0 : void apply_retpolines(s32 *start, s32 *end)
432 : {
433 0 : }
434 :
435 0 : void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
436 : {
437 0 : }
438 :
439 0 : void *text_poke(void *addr, const void *opcode, size_t len)
440 : {
441 : /*
442 : * In UML, the only reference to this function is in
443 : * apply_relocate_add(), which shouldn't ever actually call this
444 : * because UML doesn't have live patching.
445 : */
446 0 : WARN_ON(1);
447 :
448 0 : return memcpy(addr, opcode, len);
449 : }
450 :
451 0 : void text_poke_sync(void)
452 : {
453 0 : }
454 :
455 0 : void uml_pm_wake(void)
456 : {
457 0 : pm_system_wakeup();
458 0 : }
459 :
460 : #ifdef CONFIG_PM_SLEEP
461 2 : static int um_suspend_valid(suspend_state_t state)
462 : {
463 2 : return state == PM_SUSPEND_MEM;
464 : }
465 :
466 0 : static int um_suspend_prepare(void)
467 : {
468 0 : um_irqs_suspend();
469 0 : return 0;
470 : }
471 :
472 0 : static int um_suspend_enter(suspend_state_t state)
473 : {
474 0 : if (WARN_ON(state != PM_SUSPEND_MEM))
475 : return -EINVAL;
476 :
477 : /*
478 : * This is identical to the idle sleep, but we've just
479 : * (during suspend) turned off all interrupt sources
480 : * except for the ones we want, so now we can only wake
481 : * up on something we actually want to wake up on. All
482 : * timing has also been suspended.
483 : */
484 0 : um_idle_sleep();
485 0 : return 0;
486 : }
487 :
488 0 : static void um_suspend_finish(void)
489 : {
490 0 : um_irqs_resume();
491 0 : }
492 :
493 : const struct platform_suspend_ops um_suspend_ops = {
494 : .valid = um_suspend_valid,
495 : .prepare = um_suspend_prepare,
496 : .enter = um_suspend_enter,
497 : .finish = um_suspend_finish,
498 : };
499 :
500 1 : static int init_pm_wake_signal(void)
501 : {
502 : /*
503 : * In external time-travel mode we can't use signals to wake up
504 : * since that would mess with the scheduling. We'll have to do
505 : * some additional work to support wakeup on virtio devices or
506 : * similar, perhaps implementing a fake RTC controller that can
507 : * trigger wakeup (and request the appropriate scheduling from
508 : * the external scheduler when going to suspend.)
509 : */
510 : if (time_travel_mode != TT_MODE_EXTERNAL)
511 1 : register_pm_wake_signal();
512 :
513 1 : suspend_set_ops(&um_suspend_ops);
514 :
515 1 : return 0;
516 : }
517 :
518 : late_initcall(init_pm_wake_signal);
519 : #endif
|