summaryrefslogtreecommitdiffstats
path: root/common/startup.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/startup.c')
-rw-r--r--common/startup.c210
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");