KVM: x86: Loading segments on 64-bit mode may be wrong
[sfrench/cifs-2.6.git] / init / main.c
index 48655ceb66f45cdf27cf8bf769d9de296175a21c..e8ae1fef0908965b0c5fff7ba7ab8f043e83a980 100644 (file)
@@ -77,6 +77,7 @@
 #include <linux/sched_clock.h>
 #include <linux/context_tracking.h>
 #include <linux/random.h>
+#include <linux/list.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -203,13 +204,13 @@ 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;
 }
 
@@ -252,6 +253,27 @@ 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)
+{
+       unsigned int i;
+
+       if (panic_later)
+               return 0;
+
+       repair_env_string(param, val, unused);
+
+       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).
@@ -379,7 +401,7 @@ static noinline void __init_refok rest_init(void)
         * 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();
@@ -478,7 +500,7 @@ static void __init mm_init(void)
 
 asmlinkage __visible void __init start_kernel(void)
 {
-       char * command_line;
+       char * command_line, *after_dashes;
        extern const struct kernel_param __start___param[], __stop___param[];
 
        /*
@@ -507,7 +529,6 @@ asmlinkage __visible 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();
@@ -519,9 +540,13 @@ asmlinkage __visible 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, &unknown_bootoption);
+       if (after_dashes)
+               parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
+                          set_init_arg);
 
        jump_label_init();
 
@@ -616,6 +641,10 @@ asmlinkage __visible void __init start_kernel(void)
 #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();
@@ -629,9 +658,7 @@ asmlinkage __visible void __init start_kernel(void)
        signals_init();
        /* rootfs populating might need page-writeback */
        page_writeback_init();
-#ifdef CONFIG_PROC_FS
        proc_root_init();
-#endif
        cgroup_init();
        cpuset_init();
        taskstats_init_early();
@@ -666,19 +693,83 @@ static void __init do_ctors(void)
 bool initcall_debug;
 core_param(initcall_debug, initcall_debug, bool, 0644);
 
+#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)
 {
        ktime_t calltime, delta, rettime;
        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;
@@ -690,6 +781,9 @@ int __init_or_module do_one_initcall(initcall_t fn)
        int ret;
        char msgbuf[64];
 
+       if (initcall_blacklisted(fn))
+               return -EPERM;
+
        if (initcall_debug)
                ret = do_one_initcall_debug(fn);
        else