--- zzzz-none-000/linux-3.10.107/init/main.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/init/main.c 2021-02-04 17:41:59.000000000 +0000 @@ -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 + * Simplified starting of init: Michael A. Griffith */ #define DEBUG /* Enable initcall_debug */ @@ -51,7 +51,7 @@ #include #include #include -#include +#include #include #include #include @@ -74,7 +74,13 @@ #include #include #include +#include +#include #include +#include +#include +#include +#include #include #include @@ -82,25 +88,20 @@ #include #include -#ifdef CONFIG_X86_LOCAL_APIC -#include +#ifdef CONFIG_QCA_NMI_RESERVE +#include +#include #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' * where only the boot processor is running with IRQ disabled. This means @@ -122,7 +123,6 @@ 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]; @@ -130,17 +130,26 @@ 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; @@ -154,8 +163,8 @@ __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[]; @@ -194,18 +203,17 @@ * 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; } @@ -232,7 +240,8 @@ 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"? */ @@ -248,13 +257,36 @@ 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)) @@ -272,7 +304,7 @@ 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)) @@ -284,7 +316,7 @@ 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; } } @@ -324,17 +356,31 @@ #ifndef CONFIG_SMP static const unsigned int setup_max_cpus = NR_CPUS; -#ifdef CONFIG_X86_LOCAL_APIC -static void __init smp_init(void) +static inline void setup_nr_cpu_ids(void) { } +static inline void smp_prepare_cpus(unsigned int maxcpus) { } +#endif + +#ifdef CONFIG_MANGLE_BOOTARGS +static void __init mangle_bootargs(char *command_line) { - APIC_init_uniprocessor(); + char *rootdev; + char *rootfs; + + rootdev = strstr(command_line, "root=/dev/mtdblock"); + + if (rootdev) + strncpy(rootdev, "mangled_rootblock=", 18); + + rootfs = strstr(command_line, "rootfstype"); + + if (rootfs) + strncpy(rootfs, "mangled_fs", 10); + } #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) { } +static void __init mangle_bootargs(char *command_line) +{ +} #endif /* @@ -345,10 +391,13 @@ */ 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); } /* @@ -367,12 +416,13 @@ 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(); @@ -391,7 +441,8 @@ } /* 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; @@ -410,14 +461,15 @@ 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; @@ -452,33 +504,162 @@ } #endif +#ifdef CONFIG_QCA_NMI_RESERVE +/* + * WARNING: + * This will turn off memory mapped SPI flash access. + */ + +#define ENTRY_LO_MASK (~((1ul << 26) - 1)) +#define ENTRY_LO_V 0x2 +#define ENTRY_LO_G 0x1 +#define ENTRY_LO_C(x) (((x) & CONF_CM_CMASK) << 2) + +extern void local_flush_tlb_all(void); +extern void except_vec_nmi(void); + +static void *nmi_reserve; + +static __init bool use_nmi_relocation(void) { + int ret; + u32 relocation; + + ret = of_property_read_u32(of_root, "nmi-relocation", &relocation); + + if (ret != 0) { + return false; + } + + return relocation == 1; +} + +static __init int copy_nmi_trampoline(void) +{ + mm_segment_t old_fs; + extern char except_vec_nmi_end; + + if (!nmi_reserve) + return -1; + + memset(nmi_reserve, 0, PAGE_SIZE); + + memcpy(nmi_reserve, except_vec_nmi, + &except_vec_nmi_end - (char *)except_vec_nmi); + + old_fs = get_fs(); /* refer load_module() */ + set_fs(KERNEL_DS); + + /* + * This might not be needed as the region is marked as + * CONF_CM_UNCACHED. Better safe than sorry! (if that gets changed) + */ + local_flush_icache_range((unsigned long)nmi_reserve, (unsigned long)nmi_reserve + 256); + local_flush_data_cache_page(nmi_reserve); + + set_fs(old_fs); + + pr_info("[nmi] %s done\n", __func__); + + return 0; +} + +static __init void nmi_reserve_memory(void) +{ + unsigned long pa, lo0; + + nmi_reserve = vmalloc(PAGE_SIZE); + + if (!nmi_reserve) { + pr_err("[nmi] %s: ENOMEM\n", __func__); + return; + } + + if ((u32)nmi_reserve != (u32)VMALLOC_START) { + pr_err("[nmi] %s: NMI handler reserve area (%p) != %p\n", + __func__, nmi_reserve, (void*)VMALLOC_START); + vfree(nmi_reserve); + nmi_reserve = NULL; + return; + } + + /* + * When the CPU receives the NMI, it uses the reset TLB. + * Hence the 'vmalloc' mapping would not be available + * temporarily. Hence, wire that TLB entry + */ + pa = virt_to_phys(nmi_reserve); + + lo0 = (pa >> 12) << 6; // PFN + lo0 &= ~ENTRY_LO_MASK; + + lo0 |= ENTRY_LO_V | ENTRY_LO_G; + + lo0 |= ENTRY_LO_C(CONF_CM_UNCACHED); // Caching attributes + + /* + * TLB could already have the mapping for VMALLOC_START. Ideally, only + * that entry should be removed, but don't have the patience to figure + * it out :( And, since this is a one time operation during early boot, + * cleaning everything should be ok. + */ + local_flush_tlb_all(); + + add_wired_entry(lo0, lo0, (unsigned long)nmi_reserve, PM_4K); + + pr_info("[nmi] VA:PA %p:%p wired at entry 0x%x\n", + nmi_reserve, (void*)pa, read_c0_wired()); +} + +/* + * Probably should use 'board_nmi_handler_setup', but this works + */ +late_initcall(copy_nmi_trampoline); + +#if !defined(CONFIG_MTD_ATH_FLASH) +void ath_spi_disable_mm(void) { + ath_reg_wr_nf(ATH_SPI_FS, 1); +} +#endif + +#endif /* CONFIG_QCA_NMI_RESERVE */ + + /* * Set up kernel memory allocators */ 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(); +#ifdef CONFIG_QCA_NMI_RESERVE + if (use_nmi_relocation()) { + // Enable SPI soft access (and in turn disable memory mapped spi) + ath_spi_disable_mm(); + nmi_reserve_memory(); + } +#endif + 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(); @@ -500,8 +681,8 @@ page_address_init(); pr_notice("%s", linux_banner); setup_arch(&command_line); - mm_init_owner(&init_mm, &init_task); mm_init_cpumask(&init_mm); + mangle_bootargs(command_line); setup_command_line(command_line); setup_nr_cpu_ids(); setup_per_cpu_areas(); @@ -512,9 +693,13 @@ 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(); @@ -540,22 +725,29 @@ * 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"); @@ -571,7 +763,8 @@ */ console_init(); if (panic_later) - panic(panic_later, panic_param); + panic("Too many boot %s vars at `%s'", panic_later, + panic_param); lockdep_info(); @@ -591,7 +784,7 @@ initrd_start = 0; } #endif - page_cgroup_init(); + page_ext_init(); debug_objects_mem_init(); kmemleak_init(); setup_per_cpu_pageset(); @@ -602,6 +795,7 @@ calibrate_delay(); pidmap_init(); anon_vma_init(); + acpi_early_init(); #ifdef CONFIG_X86 if (efi_enabled(EFI_RUNTIME_SERVICES)) efi_enter_virtual_mode(); @@ -612,27 +806,26 @@ #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)) { @@ -660,7 +853,69 @@ 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) { @@ -668,13 +923,13 @@ 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; @@ -684,6 +939,10 @@ { int count = preempt_count(); int ret; + char msgbuf[64]; + + if (initcall_blacklisted(fn)) + return -EPERM; if (initcall_debug) ret = do_one_initcall_debug(fn); @@ -694,7 +953,7 @@ if (preempt_count() != count) { sprintf(msgbuf, "preemption imbalance "); - preempt_count() = count; + preempt_count_set(count); } if (irqs_disabled()) { strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf)); @@ -743,15 +1002,14 @@ 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); @@ -775,7 +1033,6 @@ static void __init do_basic_setup(void) { cpuset_init_smp(); - usermodehelper_init(); shmem_init(); driver_init(); init_irq_proc(); @@ -807,15 +1064,31 @@ 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); 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(); @@ -827,9 +1100,11 @@ 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); } /* @@ -839,18 +1114,20 @@ * 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("/etc/preinit") || + !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."); } @@ -883,6 +1160,8 @@ smp_init(); sched_init_smp(); + page_alloc_init_late(); + do_basic_setup(); /* Open the /dev/console on the rootfs, this should never fail */ @@ -908,8 +1187,11 @@ * 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(); }