LCOV - code coverage report
Current view: top level - arch/um/kernel - um_arch.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 97 193 50.3 %
Date: 2023-08-24 13:40:31 Functions: 12 33 36.4 %

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

Generated by: LCOV version 1.14