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

Generated by: LCOV version 1.14