183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
266ded17dSSimon Glass /*
366ded17dSSimon Glass * (C) Copyright 2000
466ded17dSSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
566ded17dSSimon Glass */
666ded17dSSimon Glass
766ded17dSSimon Glass #include <common.h>
839e1230eSJeroen Hofstee #include <autoboot.h>
90098e179SSimon Glass #include <bootretry.h>
1066ded17dSSimon Glass #include <cli.h>
1124b852a7SSimon Glass #include <console.h>
1266ded17dSSimon Glass #include <fdtdec.h>
1366ded17dSSimon Glass #include <menu.h>
1466ded17dSSimon Glass #include <post.h>
158f0b1e24SStefan Roese #include <u-boot/sha256.h>
16*bc8c440fSLukasz Majewski #include <bootcount.h>
1766ded17dSSimon Glass
1866ded17dSSimon Glass DECLARE_GLOBAL_DATA_PTR;
1966ded17dSSimon Glass
2066ded17dSSimon Glass #define MAX_DELAY_STOP_STR 32
2166ded17dSSimon Glass
2266ded17dSSimon Glass #ifndef DEBUG_BOOTKEYS
2366ded17dSSimon Glass #define DEBUG_BOOTKEYS 0
2466ded17dSSimon Glass #endif
2566ded17dSSimon Glass #define debug_bootkeys(fmt, args...) \
2666ded17dSSimon Glass debug_cond(DEBUG_BOOTKEYS, fmt, ##args)
2766ded17dSSimon Glass
28affb2156SSimon Glass /* Stored value of bootdelay, used by autoboot_command() */
29affb2156SSimon Glass static int stored_bootdelay;
30affb2156SSimon Glass
3166ded17dSSimon Glass #if defined(CONFIG_AUTOBOOT_KEYED)
328f0b1e24SStefan Roese #if defined(CONFIG_AUTOBOOT_STOP_STR_SHA256)
338f0b1e24SStefan Roese
348f0b1e24SStefan Roese /*
358f0b1e24SStefan Roese * Use a "constant-length" time compare function for this
368f0b1e24SStefan Roese * hash compare:
378f0b1e24SStefan Roese *
388f0b1e24SStefan Roese * https://crackstation.net/hashing-security.htm
398f0b1e24SStefan Roese */
slow_equals(u8 * a,u8 * b,int len)408f0b1e24SStefan Roese static int slow_equals(u8 *a, u8 *b, int len)
418f0b1e24SStefan Roese {
428f0b1e24SStefan Roese int diff = 0;
438f0b1e24SStefan Roese int i;
448f0b1e24SStefan Roese
458f0b1e24SStefan Roese for (i = 0; i < len; i++)
468f0b1e24SStefan Roese diff |= a[i] ^ b[i];
478f0b1e24SStefan Roese
488f0b1e24SStefan Roese return diff == 0;
498f0b1e24SStefan Roese }
508f0b1e24SStefan Roese
passwd_abort(uint64_t etime)518f0b1e24SStefan Roese static int passwd_abort(uint64_t etime)
528f0b1e24SStefan Roese {
5300caae6dSSimon Glass const char *sha_env_str = env_get("bootstopkeysha256");
548f0b1e24SStefan Roese u8 sha_env[SHA256_SUM_LEN];
558f0b1e24SStefan Roese u8 sha[SHA256_SUM_LEN];
568f0b1e24SStefan Roese char presskey[MAX_DELAY_STOP_STR];
578f0b1e24SStefan Roese const char *algo_name = "sha256";
588f0b1e24SStefan Roese u_int presskey_len = 0;
598f0b1e24SStefan Roese int abort = 0;
602d06fd83SMartin Etnestad int size = sizeof(sha);
618f0b1e24SStefan Roese int ret;
628f0b1e24SStefan Roese
638f0b1e24SStefan Roese if (sha_env_str == NULL)
648f0b1e24SStefan Roese sha_env_str = CONFIG_AUTOBOOT_STOP_STR_SHA256;
658f0b1e24SStefan Roese
668f0b1e24SStefan Roese /*
678f0b1e24SStefan Roese * Generate the binary value from the environment hash value
688f0b1e24SStefan Roese * so that we can compare this value with the computed hash
698f0b1e24SStefan Roese * from the user input
708f0b1e24SStefan Roese */
718f0b1e24SStefan Roese ret = hash_parse_string(algo_name, sha_env_str, sha_env);
728f0b1e24SStefan Roese if (ret) {
738f0b1e24SStefan Roese printf("Hash %s not supported!\n", algo_name);
748f0b1e24SStefan Roese return 0;
758f0b1e24SStefan Roese }
768f0b1e24SStefan Roese
778f0b1e24SStefan Roese /*
788f0b1e24SStefan Roese * We don't know how long the stop-string is, so we need to
798f0b1e24SStefan Roese * generate the sha256 hash upon each input character and
808f0b1e24SStefan Roese * compare the value with the one saved in the environment
818f0b1e24SStefan Roese */
828f0b1e24SStefan Roese do {
838f0b1e24SStefan Roese if (tstc()) {
848f0b1e24SStefan Roese /* Check for input string overflow */
858f0b1e24SStefan Roese if (presskey_len >= MAX_DELAY_STOP_STR)
868f0b1e24SStefan Roese return 0;
878f0b1e24SStefan Roese
888f0b1e24SStefan Roese presskey[presskey_len++] = getc();
898f0b1e24SStefan Roese
908f0b1e24SStefan Roese /* Calculate sha256 upon each new char */
918f0b1e24SStefan Roese hash_block(algo_name, (const void *)presskey,
928f0b1e24SStefan Roese presskey_len, sha, &size);
938f0b1e24SStefan Roese
948f0b1e24SStefan Roese /* And check if sha matches saved value in env */
958f0b1e24SStefan Roese if (slow_equals(sha, sha_env, SHA256_SUM_LEN))
968f0b1e24SStefan Roese abort = 1;
978f0b1e24SStefan Roese }
988f0b1e24SStefan Roese } while (!abort && get_ticks() <= etime);
998f0b1e24SStefan Roese
1008f0b1e24SStefan Roese return abort;
1018f0b1e24SStefan Roese }
1028f0b1e24SStefan Roese #else
passwd_abort(uint64_t etime)1038f0b1e24SStefan Roese static int passwd_abort(uint64_t etime)
10466ded17dSSimon Glass {
10566ded17dSSimon Glass int abort = 0;
10666ded17dSSimon Glass struct {
10766ded17dSSimon Glass char *str;
10866ded17dSSimon Glass u_int len;
10966ded17dSSimon Glass int retry;
11066ded17dSSimon Glass }
11166ded17dSSimon Glass delaykey[] = {
11200caae6dSSimon Glass { .str = env_get("bootdelaykey"), .retry = 1 },
11300caae6dSSimon Glass { .str = env_get("bootstopkey"), .retry = 0 },
11466ded17dSSimon Glass };
11566ded17dSSimon Glass
11666ded17dSSimon Glass char presskey[MAX_DELAY_STOP_STR];
11766ded17dSSimon Glass u_int presskey_len = 0;
11866ded17dSSimon Glass u_int presskey_max = 0;
11966ded17dSSimon Glass u_int i;
12066ded17dSSimon Glass
12166ded17dSSimon Glass # ifdef CONFIG_AUTOBOOT_DELAY_STR
12266ded17dSSimon Glass if (delaykey[0].str == NULL)
12366ded17dSSimon Glass delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
12466ded17dSSimon Glass # endif
12566ded17dSSimon Glass # ifdef CONFIG_AUTOBOOT_STOP_STR
1262d908fa0SStefan Roese if (delaykey[1].str == NULL)
1272d908fa0SStefan Roese delaykey[1].str = CONFIG_AUTOBOOT_STOP_STR;
12866ded17dSSimon Glass # endif
12966ded17dSSimon Glass
13066ded17dSSimon Glass for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
13166ded17dSSimon Glass delaykey[i].len = delaykey[i].str == NULL ?
13266ded17dSSimon Glass 0 : strlen(delaykey[i].str);
13366ded17dSSimon Glass delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
13466ded17dSSimon Glass MAX_DELAY_STOP_STR : delaykey[i].len;
13566ded17dSSimon Glass
13666ded17dSSimon Glass presskey_max = presskey_max > delaykey[i].len ?
13766ded17dSSimon Glass presskey_max : delaykey[i].len;
13866ded17dSSimon Glass
13966ded17dSSimon Glass debug_bootkeys("%s key:<%s>\n",
14066ded17dSSimon Glass delaykey[i].retry ? "delay" : "stop",
14166ded17dSSimon Glass delaykey[i].str ? delaykey[i].str : "NULL");
14266ded17dSSimon Glass }
14366ded17dSSimon Glass
14466ded17dSSimon Glass /* In order to keep up with incoming data, check timeout only
14566ded17dSSimon Glass * when catch up.
14666ded17dSSimon Glass */
14766ded17dSSimon Glass do {
14866ded17dSSimon Glass if (tstc()) {
14966ded17dSSimon Glass if (presskey_len < presskey_max) {
15066ded17dSSimon Glass presskey[presskey_len++] = getc();
15166ded17dSSimon Glass } else {
15266ded17dSSimon Glass for (i = 0; i < presskey_max - 1; i++)
15366ded17dSSimon Glass presskey[i] = presskey[i + 1];
15466ded17dSSimon Glass
15566ded17dSSimon Glass presskey[i] = getc();
15666ded17dSSimon Glass }
15766ded17dSSimon Glass }
15866ded17dSSimon Glass
15966ded17dSSimon Glass for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
16066ded17dSSimon Glass if (delaykey[i].len > 0 &&
16166ded17dSSimon Glass presskey_len >= delaykey[i].len &&
16266ded17dSSimon Glass memcmp(presskey + presskey_len -
16366ded17dSSimon Glass delaykey[i].len, delaykey[i].str,
16466ded17dSSimon Glass delaykey[i].len) == 0) {
16566ded17dSSimon Glass debug_bootkeys("got %skey\n",
16666ded17dSSimon Glass delaykey[i].retry ? "delay" :
16766ded17dSSimon Glass "stop");
16866ded17dSSimon Glass
16966ded17dSSimon Glass /* don't retry auto boot */
17066ded17dSSimon Glass if (!delaykey[i].retry)
17166ded17dSSimon Glass bootretry_dont_retry();
17266ded17dSSimon Glass abort = 1;
17366ded17dSSimon Glass }
17466ded17dSSimon Glass }
17566ded17dSSimon Glass } while (!abort && get_ticks() <= etime);
17666ded17dSSimon Glass
1778f0b1e24SStefan Roese return abort;
1788f0b1e24SStefan Roese }
1798f0b1e24SStefan Roese #endif
1808f0b1e24SStefan Roese
1818f0b1e24SStefan Roese /***************************************************************************
1828f0b1e24SStefan Roese * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
1838f0b1e24SStefan Roese * returns: 0 - no key string, allow autoboot 1 - got key string, abort
1848f0b1e24SStefan Roese */
__abortboot(int bootdelay)185d8da8298SMasahiro Yamada static int __abortboot(int bootdelay)
1868f0b1e24SStefan Roese {
1878f0b1e24SStefan Roese int abort;
1888f0b1e24SStefan Roese uint64_t etime = endtick(bootdelay);
1898f0b1e24SStefan Roese
1908f0b1e24SStefan Roese # ifdef CONFIG_AUTOBOOT_PROMPT
1918f0b1e24SStefan Roese /*
1928f0b1e24SStefan Roese * CONFIG_AUTOBOOT_PROMPT includes the %d for all boards.
1938f0b1e24SStefan Roese * To print the bootdelay value upon bootup.
1948f0b1e24SStefan Roese */
1958f0b1e24SStefan Roese printf(CONFIG_AUTOBOOT_PROMPT, bootdelay);
1968f0b1e24SStefan Roese # endif
1978f0b1e24SStefan Roese
1988f0b1e24SStefan Roese abort = passwd_abort(etime);
19966ded17dSSimon Glass if (!abort)
20066ded17dSSimon Glass debug_bootkeys("key timeout\n");
20166ded17dSSimon Glass
20266ded17dSSimon Glass return abort;
20366ded17dSSimon Glass }
20466ded17dSSimon Glass
20566ded17dSSimon Glass # else /* !defined(CONFIG_AUTOBOOT_KEYED) */
20666ded17dSSimon Glass
20766ded17dSSimon Glass #ifdef CONFIG_MENUKEY
20866ded17dSSimon Glass static int menukey;
20966ded17dSSimon Glass #endif
21066ded17dSSimon Glass
__abortboot(int bootdelay)211d8da8298SMasahiro Yamada static int __abortboot(int bootdelay)
21266ded17dSSimon Glass {
21366ded17dSSimon Glass int abort = 0;
21466ded17dSSimon Glass unsigned long ts;
21566ded17dSSimon Glass
21666ded17dSSimon Glass #ifdef CONFIG_MENUPROMPT
21766ded17dSSimon Glass printf(CONFIG_MENUPROMPT);
21866ded17dSSimon Glass #else
21966ded17dSSimon Glass printf("Hit any key to stop autoboot: %2d ", bootdelay);
22066ded17dSSimon Glass #endif
22166ded17dSSimon Glass
22266ded17dSSimon Glass /*
22366ded17dSSimon Glass * Check if key already pressed
22466ded17dSSimon Glass */
22566ded17dSSimon Glass if (tstc()) { /* we got a key press */
22666ded17dSSimon Glass (void) getc(); /* consume input */
22766ded17dSSimon Glass puts("\b\b\b 0");
22866ded17dSSimon Glass abort = 1; /* don't auto boot */
22966ded17dSSimon Glass }
23066ded17dSSimon Glass
23166ded17dSSimon Glass while ((bootdelay > 0) && (!abort)) {
23266ded17dSSimon Glass --bootdelay;
23366ded17dSSimon Glass /* delay 1000 ms */
23466ded17dSSimon Glass ts = get_timer(0);
23566ded17dSSimon Glass do {
23666ded17dSSimon Glass if (tstc()) { /* we got a key press */
23766ded17dSSimon Glass abort = 1; /* don't auto boot */
23866ded17dSSimon Glass bootdelay = 0; /* no more delay */
23966ded17dSSimon Glass # ifdef CONFIG_MENUKEY
24066ded17dSSimon Glass menukey = getc();
24166ded17dSSimon Glass # else
24266ded17dSSimon Glass (void) getc(); /* consume input */
24366ded17dSSimon Glass # endif
24466ded17dSSimon Glass break;
24566ded17dSSimon Glass }
24666ded17dSSimon Glass udelay(10000);
24766ded17dSSimon Glass } while (!abort && get_timer(ts) < 1000);
24866ded17dSSimon Glass
24966ded17dSSimon Glass printf("\b\b\b%2d ", bootdelay);
25066ded17dSSimon Glass }
25166ded17dSSimon Glass
25266ded17dSSimon Glass putc('\n');
25366ded17dSSimon Glass
25466ded17dSSimon Glass return abort;
25566ded17dSSimon Glass }
25666ded17dSSimon Glass # endif /* CONFIG_AUTOBOOT_KEYED */
25766ded17dSSimon Glass
abortboot(int bootdelay)25866ded17dSSimon Glass static int abortboot(int bootdelay)
25966ded17dSSimon Glass {
26046327392SMasahiro Yamada int abort = 0;
26109b9d9e5SMasahiro Yamada
26246327392SMasahiro Yamada if (bootdelay >= 0)
26309b9d9e5SMasahiro Yamada abort = __abortboot(bootdelay);
26409b9d9e5SMasahiro Yamada
26509b9d9e5SMasahiro Yamada #ifdef CONFIG_SILENT_CONSOLE
26609b9d9e5SMasahiro Yamada if (abort)
26709b9d9e5SMasahiro Yamada gd->flags &= ~GD_FLG_SILENT;
26809b9d9e5SMasahiro Yamada #endif
26909b9d9e5SMasahiro Yamada
27009b9d9e5SMasahiro Yamada return abort;
27166ded17dSSimon Glass }
27266ded17dSSimon Glass
process_fdt_options(const void * blob)27366ded17dSSimon Glass static void process_fdt_options(const void *blob)
27466ded17dSSimon Glass {
2759f73690cSStefan Roese #if defined(CONFIG_OF_CONTROL) && defined(CONFIG_SYS_TEXT_BASE)
27666ded17dSSimon Glass ulong addr;
27766ded17dSSimon Glass
27866ded17dSSimon Glass /* Add an env variable to point to a kernel payload, if available */
27966ded17dSSimon Glass addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0);
28066ded17dSSimon Glass if (addr)
281018f5303SSimon Glass env_set_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
28266ded17dSSimon Glass
28366ded17dSSimon Glass /* Add an env variable to point to a root disk, if available */
28466ded17dSSimon Glass addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0);
28566ded17dSSimon Glass if (addr)
286018f5303SSimon Glass env_set_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
2879f73690cSStefan Roese #endif /* CONFIG_OF_CONTROL && CONFIG_SYS_TEXT_BASE */
288affb2156SSimon Glass }
28966ded17dSSimon Glass
bootdelay_process(void)290affb2156SSimon Glass const char *bootdelay_process(void)
29166ded17dSSimon Glass {
29266ded17dSSimon Glass char *s;
29366ded17dSSimon Glass int bootdelay;
29466ded17dSSimon Glass
295*bc8c440fSLukasz Majewski bootcount_inc();
29666ded17dSSimon Glass
29700caae6dSSimon Glass s = env_get("bootdelay");
29866ded17dSSimon Glass bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
29966ded17dSSimon Glass
30066ded17dSSimon Glass #ifdef CONFIG_OF_CONTROL
30166ded17dSSimon Glass bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
30266ded17dSSimon Glass bootdelay);
30366ded17dSSimon Glass #endif
30466ded17dSSimon Glass
30566ded17dSSimon Glass debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
30666ded17dSSimon Glass
30766ded17dSSimon Glass #if defined(CONFIG_MENU_SHOW)
30866ded17dSSimon Glass bootdelay = menu_show(bootdelay);
30966ded17dSSimon Glass #endif
310b26440f1SSimon Glass bootretry_init_cmd_timeout();
31166ded17dSSimon Glass
31266ded17dSSimon Glass #ifdef CONFIG_POST
31366ded17dSSimon Glass if (gd->flags & GD_FLG_POSTFAIL) {
31400caae6dSSimon Glass s = env_get("failbootcmd");
31566ded17dSSimon Glass } else
31666ded17dSSimon Glass #endif /* CONFIG_POST */
317*bc8c440fSLukasz Majewski if (bootcount_error())
31800caae6dSSimon Glass s = env_get("altbootcmd");
319*bc8c440fSLukasz Majewski else
32000caae6dSSimon Glass s = env_get("bootcmd");
32166ded17dSSimon Glass
32266ded17dSSimon Glass process_fdt_options(gd->fdt_blob);
323affb2156SSimon Glass stored_bootdelay = bootdelay;
32466ded17dSSimon Glass
325affb2156SSimon Glass return s;
326affb2156SSimon Glass }
32766ded17dSSimon Glass
autoboot_command(const char * s)328affb2156SSimon Glass void autoboot_command(const char *s)
329affb2156SSimon Glass {
33066ded17dSSimon Glass debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
33166ded17dSSimon Glass
332affb2156SSimon Glass if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
33366ded17dSSimon Glass #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
33466ded17dSSimon Glass int prev = disable_ctrlc(1); /* disable Control C checking */
33566ded17dSSimon Glass #endif
33666ded17dSSimon Glass
33766ded17dSSimon Glass run_command_list(s, -1, 0);
33866ded17dSSimon Glass
33966ded17dSSimon Glass #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
34066ded17dSSimon Glass disable_ctrlc(prev); /* restore Control C checking */
34166ded17dSSimon Glass #endif
34266ded17dSSimon Glass }
34366ded17dSSimon Glass
34466ded17dSSimon Glass #ifdef CONFIG_MENUKEY
34566ded17dSSimon Glass if (menukey == CONFIG_MENUKEY) {
34600caae6dSSimon Glass s = env_get("menucmd");
34766ded17dSSimon Glass if (s)
34866ded17dSSimon Glass run_command_list(s, -1, 0);
34966ded17dSSimon Glass }
35066ded17dSSimon Glass #endif /* CONFIG_MENUKEY */
35166ded17dSSimon Glass }
352