diff options
Diffstat (limited to 'common/startup.c')
-rw-r--r-- | common/startup.c | 210 |
1 files changed, 112 insertions, 98 deletions
diff --git a/common/startup.c b/common/startup.c index c417a4d078..47b70a7756 100644 --- a/common/startup.c +++ b/common/startup.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * (C) Copyright 2002-2006 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. @@ -5,20 +6,6 @@ * (C) Copyright 2002 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> * Marius Groeger <mgroeger@sysgo.de> - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifdef CONFIG_DEBUG_INITCALLS @@ -37,14 +24,22 @@ #include <debug_ll.h> #include <fs.h> #include <errno.h> +#include <slice.h> #include <linux/stat.h> #include <envfs.h> +#include <magicvar.h> +#include <linux/reboot-mode.h> #include <asm/sections.h> #include <uncompress.h> #include <globalvar.h> #include <console_countdown.h> #include <environment.h> #include <linux/ctype.h> +#include <watchdog.h> +#include <glob.h> +#include <net.h> +#include <efi/efi-mode.h> +#include <bselftest.h> extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[], __barebox_initcalls_end[]; @@ -60,7 +55,7 @@ static int mount_root(void) mkdir("/tmp", 0); mount("none", "devfs", "/dev", NULL); - if (IS_ENABLED(CONFIG_FS_EFIVARFS)) { + if (IS_ENABLED(CONFIG_FS_EFIVARFS) && efi_is_payload()) { mkdir("/efivars", 0); mount("none", "efivarfs", "/efivars", NULL); } @@ -75,60 +70,6 @@ static int mount_root(void) fs_initcall(mount_root); #endif -#ifdef CONFIG_ENV_HANDLING -static int check_overlap(const char *path) -{ - struct cdev *cenv, *cdisk, *cpart; - const char *name; - - name = devpath_to_name(path); - - if (name == path) - /* - * no /dev/ in front, so *path is some file. No need to - * check further. - */ - return 0; - - cenv = cdev_by_name(name); - if (!cenv) - return -EINVAL; - - if (cenv->mtd) - return 0; - - cdisk = cenv->master; - - if (!cdisk) - return 0; - - list_for_each_entry(cpart, &cdisk->partitions, partition_entry) { - if (cpart == cenv) - continue; - - if (lregion_overlap(cpart->offset, cpart->size, - cenv->offset, cenv->size)) - goto conflict; - } - - return 0; - -conflict: - pr_err("Environment partition (0x%08llx-0x%08llx) " - "overlaps with partition %s (0x%08llx-0x%08llx), not using it\n", - cenv->offset, cenv->offset + cenv->size - 1, - cpart->name, - cpart->offset, cpart->offset + cpart->size - 1); - - return -EINVAL; -} -#else -static int check_overlap(const char *path) -{ - return 0; -} -#endif - static int load_environment(void) { const char *default_environment_path; @@ -140,14 +81,10 @@ static int load_environment(void) defaultenv_load("/env", 0); if (IS_ENABLED(CONFIG_ENV_HANDLING)) { - ret = check_overlap(default_environment_path); - if (ret) - default_environment_path_set(NULL); - else - envfs_load(default_environment_path, "/env", 0); + envfs_load(default_environment_path, "/env", 0); } else { if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT)) - pr_notice("No support for persistent environment. Using default environment"); + pr_notice("No support for persistent environment. Using default environment\n"); } nvvar_load(); @@ -163,6 +100,14 @@ static const char * const global_autoboot_abort_keys[] = { }; static int global_autoboot_timeout = 3; +static const char * const global_autoboot_states[] = { + [AUTOBOOT_COUNTDOWN] = "countdown", + [AUTOBOOT_ABORT] = "abort", + [AUTOBOOT_MENU] = "menu", + [AUTOBOOT_BOOT] = "boot", +}; +static int global_autoboot_state = AUTOBOOT_COUNTDOWN; + static bool test_abort(void) { bool do_abort = false; @@ -194,8 +139,6 @@ static bool test_abort(void) #define INITFILE "/env/bin/init" #define MENUFILE "/env/menu/mainmenu" -static enum autoboot_state autoboot_state = AUTOBOOT_UNKNOWN; - /** * set_autoboot_state - set the autoboot state * @autoboot: the state to set @@ -205,7 +148,7 @@ static enum autoboot_state autoboot_state = AUTOBOOT_UNKNOWN; */ void set_autoboot_state(enum autoboot_state autoboot) { - autoboot_state = autoboot; + global_autoboot_state = autoboot; } /** @@ -221,6 +164,7 @@ void set_autoboot_state(enum autoboot_state autoboot) */ enum autoboot_state do_autoboot_countdown(void) { + static enum autoboot_state autoboot_state = AUTOBOOT_UNKNOWN; unsigned flags = CONSOLE_COUNTDOWN_EXTERN; int ret; struct stat s; @@ -231,6 +175,15 @@ enum autoboot_state do_autoboot_countdown(void) if (autoboot_state != AUTOBOOT_UNKNOWN) return autoboot_state; + if (!console_get_first_active() && + global_autoboot_state != AUTOBOOT_ABORT) { + printf("\nNon-interactive console, booting system\n"); + return autoboot_state = AUTOBOOT_BOOT; + } + + if (global_autoboot_state != AUTOBOOT_COUNTDOWN) + return global_autoboot_state; + menu_exists = stat(MENUFILE, &s) == 0; if (menu_exists) { @@ -253,8 +206,10 @@ enum autoboot_state do_autoboot_countdown(void) break; } + command_slice_release(); ret = console_countdown(global_autoboot_timeout, flags, abortkeys, &outkey); + command_slice_acquire(); if (ret == 0) autoboot_state = AUTOBOOT_BOOT; @@ -266,27 +221,34 @@ enum autoboot_state do_autoboot_countdown(void) return autoboot_state; } -static int run_init(void) +static int register_autoboot_vars(void) { - DIR *dir; - struct dirent *d; - const char *initdir = "/env/init"; - bool env_bin_init_exists; - enum autoboot_state autoboot; - struct stat s; - - /* - * Register autoboot variables here as they might be altered by - * init scripts. - */ globalvar_add_simple_enum("autoboot_abort_key", &global_autoboot_abort_key, global_autoboot_abort_keys, ARRAY_SIZE(global_autoboot_abort_keys)); globalvar_add_simple_int("autoboot_timeout", &global_autoboot_timeout, "%u"); + globalvar_add_simple_enum("autoboot", + &global_autoboot_state, + global_autoboot_states, + ARRAY_SIZE(global_autoboot_states)); + + return 0; +} +postcore_initcall(register_autoboot_vars); + +static int run_init(void) +{ + const char *bmode; + bool env_bin_init_exists; + enum autoboot_state autoboot; + struct stat s; + glob_t g; + int i, ret; setenv("PATH", "/env/bin"); + export("PATH"); /* Run legacy /env/bin/init if it exists */ env_bin_init_exists = stat(INITFILE, &s) == 0; @@ -305,21 +267,40 @@ static int run_init(void) } /* Run scripts in /env/init/ */ - dir = opendir(initdir); - if (dir) { - char *scr; + ret = glob("/env/init/*", 0, NULL, &g); + if (!ret) { + for (i = 0; i < g.gl_pathc; i++) { + const char *path = g.gl_pathv[i]; + char *scr; + + ret = stat(path, &s); + if (ret) + continue; - while ((d = readdir(dir))) { - if (*d->d_name == '.') + if (!S_ISREG(s.st_mode)) continue; - pr_debug("Executing '%s/%s'...\n", initdir, d->d_name); - scr = basprintf("source %s/%s", initdir, d->d_name); + pr_debug("Executing '%s'...\n", path); + scr = basprintf("source %s", path); run_command(scr); free(scr); } - closedir(dir); + globfree(&g); + } + + /* source matching script in /env/bmode/ */ + bmode = reboot_mode_get(); + if (bmode) { + char *scr, *path; + + scr = xasprintf("source /env/bmode/%s", bmode); + path = &scr[strlen("source ")]; + if (stat(path, &s) == 0) { + pr_info("Invoking '%s'...\n", path); + run_command(scr); + } + free(scr); } autoboot = do_autoboot_countdown(); @@ -329,15 +310,34 @@ static int run_init(void) if (autoboot == AUTOBOOT_BOOT) run_command("boot"); + if (IS_ENABLED(CONFIG_NET)) + eth_open_all(); + if (autoboot == AUTOBOOT_MENU) run_command(MENUFILE); + if (autoboot == AUTOBOOT_ABORT && autoboot == global_autoboot_state) + watchdog_inhibit_all(); + run_shell(); run_command(MENUFILE); return 0; } +typedef void (*ctor_fn_t)(void); + +/* Call all constructor functions linked into the kernel. */ +static void do_ctors(void) +{ +#ifdef CONFIG_CONSTRUCTORS + ctor_fn_t *fn = (ctor_fn_t *) __ctors_start; + + for (; fn < (ctor_fn_t *) __ctors_end; fn++) + (*fn)(); +#endif +} + int (*barebox_main)(void); void __noreturn start_barebox(void) @@ -348,6 +348,8 @@ void __noreturn start_barebox(void) if (!IS_ENABLED(CONFIG_SHELL_NONE) && IS_ENABLED(CONFIG_COMMAND_SUPPORT)) barebox_main = run_init; + do_ctors(); + for (initcall = __barebox_initcalls_start; initcall < __barebox_initcalls_end; initcall++) { pr_debug("initcall-> %pS\n", *initcall); @@ -359,6 +361,9 @@ void __noreturn start_barebox(void) pr_debug("initcalls done\n"); + if (IS_ENABLED(CONFIG_SELFTEST_AUTORUN)) + selftests_run(); + if (barebox_main) barebox_main(); @@ -390,4 +395,13 @@ void shutdown_barebox(void) pr_debug("exitcall-> %pS\n", *exitcall); (*exitcall)(); } + + console_flush(); } + +BAREBOX_MAGICVAR(global.autoboot, + "Autoboot state. Possible values: countdown (default), abort, menu, boot"); +BAREBOX_MAGICVAR(global.autoboot_abort_key, + "Which key allows to interrupt autoboot. Possible values: any, ctrl-c"); +BAREBOX_MAGICVAR(global.autoboot_timeout, + "Timeout before autoboot starts in seconds"); |