video/rga: fix rga support flip
[firefly-linux-kernel-4.4.55.git] / init / main.c
index 9484f4ba88d05aa589bb737d96836a1a01db55ce..fbafa271531cb417a60bb1366baacc04f2e81880 100644 (file)
@@ -6,7 +6,7 @@
  *  GK 2/5/95  -  Changed to support mounting root fs via NFS
  *  Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96
  *  Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96
- *  Simplified starting of init:  Michael A. Griffith <grif@acm.org> 
+ *  Simplified starting of init:  Michael A. Griffith <grif@acm.org>
  */
 
 #define DEBUG          /* Enable initcall_debug */
@@ -51,7 +51,7 @@
 #include <linux/mempolicy.h>
 #include <linux/key.h>
 #include <linux/buffer_head.h>
-#include <linux/page_cgroup.h>
+#include <linux/page_ext.h>
 #include <linux/debug_locks.h>
 #include <linux/debugobjects.h>
 #include <linux/lockdep.h>
 #include <linux/ptrace.h>
 #include <linux/blkdev.h>
 #include <linux/elevator.h>
+#include <linux/sched_clock.h>
+#include <linux/context_tracking.h>
+#include <linux/random.h>
+#include <linux/list.h>
+#include <linux/integrity.h>
+#include <linux/proc_ns.h>
+#include <linux/io.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
 #include <asm/sections.h>
 #include <asm/cacheflush.h>
 
-#ifdef CONFIG_X86_LOCAL_APIC
-#include <asm/smp.h>
-#endif
-
 static int kernel_init(void *);
 
 extern void init_IRQ(void);
-extern void fork_init(unsigned long);
-extern void mca_init(void);
-extern void sbus_init(void);
+extern void fork_init(void);
 extern void radix_tree_init(void);
-#ifndef CONFIG_DEBUG_RODATA
-static inline void mark_rodata_ro(void) { }
-#endif
-
-#ifdef CONFIG_TC
-extern void tc_init(void);
-#endif
 
 /*
  * Debug helper: via this flag we know that we are in 'early bootup code'
@@ -121,7 +115,6 @@ EXPORT_SYMBOL(system_state);
 extern void time_init(void);
 /* Default late time init is NULL. archs can override this later. */
 void (*__initdata late_time_init)(void);
-extern void softirq_init(void);
 
 /* Untouched command line saved by arch-specific code. */
 char __initdata boot_command_line[COMMAND_LINE_SIZE];
@@ -129,17 +122,26 @@ char __initdata boot_command_line[COMMAND_LINE_SIZE];
 char *saved_command_line;
 /* Command line for parameter parsing */
 static char *static_command_line;
+/* Command line for per-initcall parameter parsing */
+static char *initcall_command_line;
 
 static char *execute_command;
 static char *ramdisk_execute_command;
 
+/*
+ * Used to generate warnings if static_key manipulation functions are used
+ * before jump_label_init is called.
+ */
+bool static_key_initialized __read_mostly;
+EXPORT_SYMBOL_GPL(static_key_initialized);
+
 /*
  * If set, this is an indication to the drivers that reset the underlying
  * device before going ahead with the initialization otherwise driver might
  * rely on the BIOS and skip the reset operation.
  *
  * This is useful if kernel is booting in an unreliable environment.
- * For ex. kdump situaiton where previous kernel has crashed, BIOS has been
+ * For ex. kdump situation where previous kernel has crashed, BIOS has been
  * skipped and devices will be in unknown state.
  */
 unsigned int reset_devices;
@@ -153,8 +155,8 @@ static int __init set_reset_devices(char *str)
 
 __setup("reset_devices", set_reset_devices);
 
-static const char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
-const char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
+static const char *argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
+const char *envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
 static const char *panic_later, *panic_param;
 
 extern const struct obs_kernel_param __setup_start[], __setup_end[];
@@ -193,18 +195,17 @@ static int __init obsolete_checksetup(char *line)
  * still work even if initially too large, it will just take slightly longer
  */
 unsigned long loops_per_jiffy = (1<<12);
-
 EXPORT_SYMBOL(loops_per_jiffy);
 
 static int __init debug_kernel(char *str)
 {
-       console_loglevel = 10;
+       console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
        return 0;
 }
 
 static int __init quiet_kernel(char *str)
 {
-       console_loglevel = 4;
+       console_loglevel = CONSOLE_LOGLEVEL_QUIET;
        return 0;
 }
 
@@ -231,7 +232,8 @@ static int __init loglevel(char *str)
 early_param("loglevel", loglevel);
 
 /* Change NUL term back to "=", to make "param" the whole string. */
-static int __init repair_env_string(char *param, char *val, const char *unused)
+static int __init repair_env_string(char *param, char *val,
+                                   const char *unused, void *arg)
 {
        if (val) {
                /* param=val or param="val"? */
@@ -247,13 +249,36 @@ static int __init repair_env_string(char *param, char *val, const char *unused)
        return 0;
 }
 
+/* Anything after -- gets handed straight to init. */
+static int __init set_init_arg(char *param, char *val,
+                              const char *unused, void *arg)
+{
+       unsigned int i;
+
+       if (panic_later)
+               return 0;
+
+       repair_env_string(param, val, unused, NULL);
+
+       for (i = 0; argv_init[i]; i++) {
+               if (i == MAX_INIT_ARGS) {
+                       panic_later = "init";
+                       panic_param = param;
+                       return 0;
+               }
+       }
+       argv_init[i] = param;
+       return 0;
+}
+
 /*
  * Unknown boot options get handed to init, unless they look like
  * unused parameters (modprobe will find them in /proc/cmdline).
  */
-static int __init unknown_bootoption(char *param, char *val, const char *unused)
+static int __init unknown_bootoption(char *param, char *val,
+                                    const char *unused, void *arg)
 {
-       repair_env_string(param, val, unused);
+       repair_env_string(param, val, unused, NULL);
 
        /* Handle obsolete-style parameters */
        if (obsolete_checksetup(param))
@@ -271,7 +296,7 @@ static int __init unknown_bootoption(char *param, char *val, const char *unused)
                unsigned int i;
                for (i = 0; envp_init[i]; i++) {
                        if (i == MAX_INIT_ENVS) {
-                               panic_later = "Too many boot env vars at `%s'";
+                               panic_later = "env";
                                panic_param = param;
                        }
                        if (!strncmp(param, envp_init[i], val - param))
@@ -283,7 +308,7 @@ static int __init unknown_bootoption(char *param, char *val, const char *unused)
                unsigned int i;
                for (i = 0; argv_init[i]; i++) {
                        if (i == MAX_INIT_ARGS) {
-                               panic_later = "Too many boot init vars at `%s'";
+                               panic_later = "init";
                                panic_param = param;
                        }
                }
@@ -323,15 +348,6 @@ __setup("rdinit=", rdinit_setup);
 
 #ifndef CONFIG_SMP
 static const unsigned int setup_max_cpus = NR_CPUS;
-#ifdef CONFIG_X86_LOCAL_APIC
-static void __init smp_init(void)
-{
-       APIC_init_uniprocessor();
-}
-#else
-#define smp_init()     do { } while (0)
-#endif
-
 static inline void setup_nr_cpu_ids(void) { }
 static inline void smp_prepare_cpus(unsigned int maxcpus) { }
 #endif
@@ -344,10 +360,13 @@ static inline void smp_prepare_cpus(unsigned int maxcpus) { }
  */
 static void __init setup_command_line(char *command_line)
 {
-       saved_command_line = alloc_bootmem(strlen (boot_command_line)+1);
-       static_command_line = alloc_bootmem(strlen (command_line)+1);
-       strcpy (saved_command_line, boot_command_line);
-       strcpy (static_command_line, command_line);
+       saved_command_line =
+               memblock_virt_alloc(strlen(boot_command_line) + 1, 0);
+       initcall_command_line =
+               memblock_virt_alloc(strlen(boot_command_line) + 1, 0);
+       static_command_line = memblock_virt_alloc(strlen(command_line) + 1, 0);
+       strcpy(saved_command_line, boot_command_line);
+       strcpy(static_command_line, command_line);
 }
 
 /*
@@ -366,12 +385,13 @@ static noinline void __init_refok rest_init(void)
        int pid;
 
        rcu_scheduler_starting();
+       smpboot_thread_init();
        /*
         * We need to spawn init first so that it obtains pid 1, however
         * the init task will end up wanting to create kthreads, which, if
         * we schedule it before we create kthreadd, will OOPS.
         */
-       kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
+       kernel_thread(kernel_init, NULL, CLONE_FS);
        numa_default_policy();
        pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
        rcu_read_lock();
@@ -390,7 +410,8 @@ static noinline void __init_refok rest_init(void)
 }
 
 /* Check for early params. */
-static int __init do_early_param(char *param, char *val, const char *unused)
+static int __init do_early_param(char *param, char *val,
+                                const char *unused, void *arg)
 {
        const struct obs_kernel_param *p;
 
@@ -409,14 +430,15 @@ static int __init do_early_param(char *param, char *val, const char *unused)
 
 void __init parse_early_options(char *cmdline)
 {
-       parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param);
+       parse_args("early options", cmdline, NULL, 0, 0, 0, NULL,
+                  do_early_param);
 }
 
 /* Arch code calls this early on, or if not, just before other parsing. */
 void __init parse_early_param(void)
 {
-       static __initdata int done = 0;
-       static __initdata char tmp_cmdline[COMMAND_LINE_SIZE];
+       static int done __initdata;
+       static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata;
 
        if (done)
                return;
@@ -457,27 +479,29 @@ void __init __weak thread_info_cache_init(void)
 static void __init mm_init(void)
 {
        /*
-        * page_cgroup requires contiguous pages,
+        * page_ext requires contiguous pages,
         * bigger than MAX_ORDER unless SPARSEMEM.
         */
-       page_cgroup_init_flatmem();
+       page_ext_init_flatmem();
        mem_init();
        kmem_cache_init();
        percpu_init_late();
-       pgtable_cache_init();
+       pgtable_init();
        vmalloc_init();
+       ioremap_huge_init();
 }
 
-asmlinkage void __init start_kernel(void)
+asmlinkage __visible void __init start_kernel(void)
 {
-       char * command_line;
-       extern const struct kernel_param __start___param[], __stop___param[];
+       char *command_line;
+       char *after_dashes;
 
        /*
         * Need to run as early as possible, to initialize the
         * lockdep hash:
         */
        lockdep_init();
+       set_task_stack_end_magic(&init_task);
        smp_setup_processor_id();
        debug_objects_early_init();
 
@@ -499,7 +523,6 @@ asmlinkage void __init start_kernel(void)
        page_address_init();
        pr_notice("%s", linux_banner);
        setup_arch(&command_line);
-       mm_init_owner(&init_mm, &init_task);
        mm_init_cpumask(&init_mm);
        setup_command_line(command_line);
        setup_nr_cpu_ids();
@@ -511,9 +534,13 @@ asmlinkage void __init start_kernel(void)
 
        pr_notice("Kernel command line: %s\n", boot_command_line);
        parse_early_param();
-       parse_args("Booting kernel", static_command_line, __start___param,
-                  __stop___param - __start___param,
-                  -1, -1, &unknown_bootoption);
+       after_dashes = parse_args("Booting kernel",
+                                 static_command_line, __start___param,
+                                 __stop___param - __start___param,
+                                 -1, -1, NULL, &unknown_bootoption);
+       if (!IS_ERR_OR_NULL(after_dashes))
+               parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
+                          NULL, set_init_arg);
 
        jump_label_init();
 
@@ -539,22 +566,29 @@ asmlinkage void __init start_kernel(void)
         * fragile until we cpu_idle() for the first time.
         */
        preempt_disable();
-       if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n"))
+       if (WARN(!irqs_disabled(),
+                "Interrupts were enabled *very* early, fixing it\n"))
                local_irq_disable();
        idr_init_cache();
-       perf_event_init();
        rcu_init();
-       tick_nohz_init();
+
+       /* trace_printk() and trace points may be used after this */
+       trace_init();
+
+       context_tracking_init();
        radix_tree_init();
        /* init some links before init_ISA_irqs() */
        early_irq_init();
        init_IRQ();
        tick_init();
+       rcu_init_nohz();
        init_timers();
        hrtimers_init();
        softirq_init();
        timekeeping_init();
        time_init();
+       sched_clock_postinit();
+       perf_event_init();
        profile_init();
        call_function_init();
        WARN(!irqs_disabled(), "Interrupts were enabled early\n");
@@ -570,7 +604,8 @@ asmlinkage void __init start_kernel(void)
         */
        console_init();
        if (panic_later)
-               panic(panic_later, panic_param);
+               panic("Too many boot %s vars at `%s'", panic_later,
+                     panic_param);
 
        lockdep_info();
 
@@ -590,7 +625,7 @@ asmlinkage void __init start_kernel(void)
                initrd_start = 0;
        }
 #endif
-       page_cgroup_init();
+       page_ext_init();
        debug_objects_mem_init();
        kmemleak_init();
        setup_per_cpu_pageset();
@@ -601,33 +636,37 @@ asmlinkage void __init start_kernel(void)
        calibrate_delay();
        pidmap_init();
        anon_vma_init();
+       acpi_early_init();
 #ifdef CONFIG_X86
        if (efi_enabled(EFI_RUNTIME_SERVICES))
                efi_enter_virtual_mode();
+#endif
+#ifdef CONFIG_X86_ESPFIX64
+       /* Should be run before the first non-init thread is created */
+       init_espfix_bsp();
 #endif
        thread_info_cache_init();
        cred_init();
-       fork_init(totalram_pages);
+       fork_init();
        proc_caches_init();
        buffer_init();
        key_init();
        security_init();
        dbg_late_init();
-       vfs_caches_init(totalram_pages);
+       vfs_caches_init();
        signals_init();
        /* rootfs populating might need page-writeback */
        page_writeback_init();
-#ifdef CONFIG_PROC_FS
        proc_root_init();
-#endif
-       cgroup_init();
+       nsfs_init();
        cpuset_init();
+       cgroup_init();
        taskstats_init_early();
        delayacct_init();
 
        check_bugs();
 
-       acpi_early_init(); /* before LAPIC and SMP init */
+       acpi_subsystem_init();
        sfi_init_late();
 
        if (efi_enabled(EFI_RUNTIME_SERVICES)) {
@@ -655,7 +694,69 @@ static void __init do_ctors(void)
 bool initcall_debug;
 core_param(initcall_debug, initcall_debug, bool, 0644);
 
-static char msgbuf[64];
+#ifdef CONFIG_KALLSYMS
+struct blacklist_entry {
+       struct list_head next;
+       char *buf;
+};
+
+static __initdata_or_module LIST_HEAD(blacklisted_initcalls);
+
+static int __init initcall_blacklist(char *str)
+{
+       char *str_entry;
+       struct blacklist_entry *entry;
+
+       /* str argument is a comma-separated list of functions */
+       do {
+               str_entry = strsep(&str, ",");
+               if (str_entry) {
+                       pr_debug("blacklisting initcall %s\n", str_entry);
+                       entry = alloc_bootmem(sizeof(*entry));
+                       entry->buf = alloc_bootmem(strlen(str_entry) + 1);
+                       strcpy(entry->buf, str_entry);
+                       list_add(&entry->next, &blacklisted_initcalls);
+               }
+       } while (str_entry);
+
+       return 0;
+}
+
+static bool __init_or_module initcall_blacklisted(initcall_t fn)
+{
+       struct list_head *tmp;
+       struct blacklist_entry *entry;
+       char *fn_name;
+
+       fn_name = kasprintf(GFP_KERNEL, "%pf", fn);
+       if (!fn_name)
+               return false;
+
+       list_for_each(tmp, &blacklisted_initcalls) {
+               entry = list_entry(tmp, struct blacklist_entry, next);
+               if (!strcmp(fn_name, entry->buf)) {
+                       pr_debug("initcall %s blacklisted\n", fn_name);
+                       kfree(fn_name);
+                       return true;
+               }
+       }
+
+       kfree(fn_name);
+       return false;
+}
+#else
+static int __init initcall_blacklist(char *str)
+{
+       pr_warn("initcall_blacklist requires CONFIG_KALLSYMS\n");
+       return 0;
+}
+
+static bool __init_or_module initcall_blacklisted(initcall_t fn)
+{
+       return false;
+}
+#endif
+__setup("initcall_blacklist=", initcall_blacklist);
 
 static int __init_or_module do_one_initcall_debug(initcall_t fn)
 {
@@ -663,13 +764,13 @@ static int __init_or_module do_one_initcall_debug(initcall_t fn)
        unsigned long long duration;
        int ret;
 
-       pr_debug("calling  %pF @ %i\n", fn, task_pid_nr(current));
+       printk(KERN_DEBUG "calling  %pF @ %i\n", fn, task_pid_nr(current));
        calltime = ktime_get();
        ret = fn();
        rettime = ktime_get();
        delta = ktime_sub(rettime, calltime);
        duration = (unsigned long long) ktime_to_ns(delta) >> 10;
-       pr_debug("initcall %pF returned %d after %lld usecs\n",
+       printk(KERN_DEBUG "initcall %pF returned %d after %lld usecs\n",
                 fn, ret, duration);
 
        return ret;
@@ -679,6 +780,10 @@ int __init_or_module do_one_initcall(initcall_t fn)
 {
        int count = preempt_count();
        int ret;
+       char msgbuf[64];
+
+       if (initcall_blacklisted(fn))
+               return -EPERM;
 
        if (initcall_debug)
                ret = do_one_initcall_debug(fn);
@@ -689,7 +794,7 @@ int __init_or_module do_one_initcall(initcall_t fn)
 
        if (preempt_count() != count) {
                sprintf(msgbuf, "preemption imbalance ");
-               preempt_count() = count;
+               preempt_count_set(count);
        }
        if (irqs_disabled()) {
                strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
@@ -738,15 +843,14 @@ static char *initcall_level_names[] __initdata = {
 
 static void __init do_initcall_level(int level)
 {
-       extern const struct kernel_param __start___param[], __stop___param[];
        initcall_t *fn;
 
-       strcpy(static_command_line, saved_command_line);
+       strcpy(initcall_command_line, saved_command_line);
        parse_args(initcall_level_names[level],
-                  static_command_line, __start___param,
+                  initcall_command_line, __start___param,
                   __stop___param - __start___param,
                   level, level,
-                  &repair_env_string);
+                  NULL, &repair_env_string);
 
        for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
                do_one_initcall(*fn);
@@ -770,13 +874,13 @@ static void __init do_initcalls(void)
 static void __init do_basic_setup(void)
 {
        cpuset_init_smp();
-       usermodehelper_init();
        shmem_init();
        driver_init();
        init_irq_proc();
        do_ctors();
        usermodehelper_enable();
        do_initcalls();
+       random_int_secret_init();
 }
 
 static void __init do_pre_smp_initcalls(void)
@@ -801,29 +905,69 @@ void __init load_default_modules(void)
 static int run_init_process(const char *init_filename)
 {
        argv_init[0] = init_filename;
-       return do_execve(init_filename,
+       return do_execve(getname_kernel(init_filename),
                (const char __user *const __user *)argv_init,
                (const char __user *const __user *)envp_init);
 }
 
+static int try_to_run_init_process(const char *init_filename)
+{
+       int ret;
+
+       ret = run_init_process(init_filename);
+
+       if (ret && ret != -ENOENT) {
+               pr_err("Starting init: %s exists but couldn't execute it (error %d)\n",
+                      init_filename, ret);
+       }
+
+       return ret;
+}
+
 static noinline void __init kernel_init_freeable(void);
 
+#ifdef CONFIG_DEBUG_RODATA
+static bool rodata_enabled = true;
+static int __init set_debug_rodata(char *str)
+{
+       return strtobool(str, &rodata_enabled);
+}
+__setup("rodata=", set_debug_rodata);
+
+static void mark_readonly(void)
+{
+       if (rodata_enabled)
+               mark_rodata_ro();
+       else
+               pr_info("Kernel memory protection disabled.\n");
+}
+#else
+static inline void mark_readonly(void)
+{
+       pr_warn("This architecture does not have kernel memory protection.\n");
+}
+#endif
+
 static int __ref kernel_init(void *unused)
 {
+       int ret;
+
        kernel_init_freeable();
        /* need to finish all async __init code before freeing the memory */
        async_synchronize_full();
        free_initmem();
-       mark_rodata_ro();
+       mark_readonly();
        system_state = SYSTEM_RUNNING;
        numa_default_policy();
 
        flush_delayed_fput();
 
        if (ramdisk_execute_command) {
-               if (!run_init_process(ramdisk_execute_command))
+               ret = run_init_process(ramdisk_execute_command);
+               if (!ret)
                        return 0;
-               pr_err("Failed to execute %s\n", ramdisk_execute_command);
+               pr_err("Failed to execute %s (error %d)\n",
+                      ramdisk_execute_command, ret);
        }
 
        /*
@@ -833,18 +977,19 @@ static int __ref kernel_init(void *unused)
         * trying to recover a really broken machine.
         */
        if (execute_command) {
-               if (!run_init_process(execute_command))
+               ret = run_init_process(execute_command);
+               if (!ret)
                        return 0;
-               pr_err("Failed to execute %s.  Attempting defaults...\n",
-                       execute_command);
+               panic("Requested init %s failed (error %d).",
+                     execute_command, ret);
        }
-       if (!run_init_process("/sbin/init") ||
-           !run_init_process("/etc/init") ||
-           !run_init_process("/bin/init") ||
-           !run_init_process("/bin/sh"))
+       if (!try_to_run_init_process("/sbin/init") ||
+           !try_to_run_init_process("/etc/init") ||
+           !try_to_run_init_process("/bin/init") ||
+           !try_to_run_init_process("/bin/sh"))
                return 0;
 
-       panic("No init found.  Try passing init= option to kernel. "
+       panic("No working init found.  Try passing init= option to kernel. "
              "See Linux Documentation/init.txt for guidance.");
 }
 
@@ -877,6 +1022,8 @@ static noinline void __init kernel_init_freeable(void)
        smp_init();
        sched_init_smp();
 
+       page_alloc_init_late();
+
        do_basic_setup();
 
        /* Open the /dev/console on the rootfs, this should never fail */
@@ -902,8 +1049,11 @@ static noinline void __init kernel_init_freeable(void)
         * Ok, we have completed the initial bootup, and
         * we're essentially up and running. Get rid of the
         * initmem segments and start the user-mode stuff..
+        *
+        * rootfs is available now, try loading the public keys
+        * and default modules
         */
 
-       /* rootfs is available now, try loading default modules */
+       integrity_load_keys();
        load_default_modules();
 }