166ded17dSSimon Glass /* 266ded17dSSimon Glass * (C) Copyright 2000 366ded17dSSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 466ded17dSSimon Glass * 566ded17dSSimon Glass * SPDX-License-Identifier: GPL-2.0+ 666ded17dSSimon Glass */ 766ded17dSSimon Glass 866ded17dSSimon Glass #include <common.h> 939e1230eSJeroen Hofstee #include <autoboot.h> 100098e179SSimon Glass #include <bootretry.h> 1166ded17dSSimon Glass #include <cli.h> 1224b852a7SSimon Glass #include <console.h> 1366ded17dSSimon Glass #include <fdtdec.h> 1466ded17dSSimon Glass #include <menu.h> 1566ded17dSSimon Glass #include <post.h> 168f0b1e24SStefan Roese #include <u-boot/sha256.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 */ 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 518f0b1e24SStefan Roese static int passwd_abort(uint64_t etime) 528f0b1e24SStefan Roese { 538f0b1e24SStefan Roese const char *sha_env_str = getenv("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; 608f0b1e24SStefan Roese int size; 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 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[] = { 1129e546ee9SJeroen Hofstee { .str = getenv("bootdelaykey"), .retry = 1 }, 1139e546ee9SJeroen Hofstee { .str = getenv("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 */ 1858f0b1e24SStefan Roese static int abortboot_keyed(int bootdelay) 1868f0b1e24SStefan Roese { 1878f0b1e24SStefan Roese int abort; 1888f0b1e24SStefan Roese uint64_t etime = endtick(bootdelay); 1898f0b1e24SStefan Roese 1908f0b1e24SStefan Roese #ifndef CONFIG_ZERO_BOOTDELAY_CHECK 1918f0b1e24SStefan Roese if (bootdelay == 0) 1928f0b1e24SStefan Roese return 0; 1938f0b1e24SStefan Roese #endif 1948f0b1e24SStefan Roese 1958f0b1e24SStefan Roese # ifdef CONFIG_AUTOBOOT_PROMPT 1968f0b1e24SStefan Roese /* 1978f0b1e24SStefan Roese * CONFIG_AUTOBOOT_PROMPT includes the %d for all boards. 1988f0b1e24SStefan Roese * To print the bootdelay value upon bootup. 1998f0b1e24SStefan Roese */ 2008f0b1e24SStefan Roese printf(CONFIG_AUTOBOOT_PROMPT, bootdelay); 2018f0b1e24SStefan Roese # endif 2028f0b1e24SStefan Roese 2038f0b1e24SStefan Roese abort = passwd_abort(etime); 20466ded17dSSimon Glass if (!abort) 20566ded17dSSimon Glass debug_bootkeys("key timeout\n"); 20666ded17dSSimon Glass 20766ded17dSSimon Glass #ifdef CONFIG_SILENT_CONSOLE 20866ded17dSSimon Glass if (abort) 20966ded17dSSimon Glass gd->flags &= ~GD_FLG_SILENT; 21066ded17dSSimon Glass #endif 21166ded17dSSimon Glass 21266ded17dSSimon Glass return abort; 21366ded17dSSimon Glass } 21466ded17dSSimon Glass 21566ded17dSSimon Glass # else /* !defined(CONFIG_AUTOBOOT_KEYED) */ 21666ded17dSSimon Glass 21766ded17dSSimon Glass #ifdef CONFIG_MENUKEY 21866ded17dSSimon Glass static int menukey; 21966ded17dSSimon Glass #endif 22066ded17dSSimon Glass 22166ded17dSSimon Glass static int abortboot_normal(int bootdelay) 22266ded17dSSimon Glass { 22366ded17dSSimon Glass int abort = 0; 22466ded17dSSimon Glass unsigned long ts; 22566ded17dSSimon Glass 22666ded17dSSimon Glass #ifdef CONFIG_MENUPROMPT 22766ded17dSSimon Glass printf(CONFIG_MENUPROMPT); 22866ded17dSSimon Glass #else 22966ded17dSSimon Glass if (bootdelay >= 0) 23066ded17dSSimon Glass printf("Hit any key to stop autoboot: %2d ", bootdelay); 23166ded17dSSimon Glass #endif 23266ded17dSSimon Glass 23366ded17dSSimon Glass #if defined CONFIG_ZERO_BOOTDELAY_CHECK 23466ded17dSSimon Glass /* 23566ded17dSSimon Glass * Check if key already pressed 23666ded17dSSimon Glass * Don't check if bootdelay < 0 23766ded17dSSimon Glass */ 23866ded17dSSimon Glass if (bootdelay >= 0) { 23966ded17dSSimon Glass if (tstc()) { /* we got a key press */ 24066ded17dSSimon Glass (void) getc(); /* consume input */ 24166ded17dSSimon Glass puts("\b\b\b 0"); 24266ded17dSSimon Glass abort = 1; /* don't auto boot */ 24366ded17dSSimon Glass } 24466ded17dSSimon Glass } 24566ded17dSSimon Glass #endif 24666ded17dSSimon Glass 24766ded17dSSimon Glass while ((bootdelay > 0) && (!abort)) { 24866ded17dSSimon Glass --bootdelay; 24966ded17dSSimon Glass /* delay 1000 ms */ 25066ded17dSSimon Glass ts = get_timer(0); 25166ded17dSSimon Glass do { 25266ded17dSSimon Glass if (tstc()) { /* we got a key press */ 25366ded17dSSimon Glass abort = 1; /* don't auto boot */ 25466ded17dSSimon Glass bootdelay = 0; /* no more delay */ 25566ded17dSSimon Glass # ifdef CONFIG_MENUKEY 25666ded17dSSimon Glass menukey = getc(); 25766ded17dSSimon Glass # else 25866ded17dSSimon Glass (void) getc(); /* consume input */ 25966ded17dSSimon Glass # endif 26066ded17dSSimon Glass break; 26166ded17dSSimon Glass } 26266ded17dSSimon Glass udelay(10000); 26366ded17dSSimon Glass } while (!abort && get_timer(ts) < 1000); 26466ded17dSSimon Glass 26566ded17dSSimon Glass printf("\b\b\b%2d ", bootdelay); 26666ded17dSSimon Glass } 26766ded17dSSimon Glass 26866ded17dSSimon Glass putc('\n'); 26966ded17dSSimon Glass 27066ded17dSSimon Glass #ifdef CONFIG_SILENT_CONSOLE 27166ded17dSSimon Glass if (abort) 27266ded17dSSimon Glass gd->flags &= ~GD_FLG_SILENT; 27366ded17dSSimon Glass #endif 27466ded17dSSimon Glass 27566ded17dSSimon Glass return abort; 27666ded17dSSimon Glass } 27766ded17dSSimon Glass # endif /* CONFIG_AUTOBOOT_KEYED */ 27866ded17dSSimon Glass 27966ded17dSSimon Glass static int abortboot(int bootdelay) 28066ded17dSSimon Glass { 28166ded17dSSimon Glass #ifdef CONFIG_AUTOBOOT_KEYED 28266ded17dSSimon Glass return abortboot_keyed(bootdelay); 28366ded17dSSimon Glass #else 28466ded17dSSimon Glass return abortboot_normal(bootdelay); 28566ded17dSSimon Glass #endif 28666ded17dSSimon Glass } 28766ded17dSSimon Glass 28866ded17dSSimon Glass static void process_fdt_options(const void *blob) 28966ded17dSSimon Glass { 290*9f73690cSStefan Roese #if defined(CONFIG_OF_CONTROL) && defined(CONFIG_SYS_TEXT_BASE) 29166ded17dSSimon Glass ulong addr; 29266ded17dSSimon Glass 29366ded17dSSimon Glass /* Add an env variable to point to a kernel payload, if available */ 29466ded17dSSimon Glass addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0); 29566ded17dSSimon Glass if (addr) 29666ded17dSSimon Glass setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); 29766ded17dSSimon Glass 29866ded17dSSimon Glass /* Add an env variable to point to a root disk, if available */ 29966ded17dSSimon Glass addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0); 30066ded17dSSimon Glass if (addr) 30166ded17dSSimon Glass setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); 302*9f73690cSStefan Roese #endif /* CONFIG_OF_CONTROL && CONFIG_SYS_TEXT_BASE */ 303affb2156SSimon Glass } 30466ded17dSSimon Glass 305affb2156SSimon Glass const char *bootdelay_process(void) 30666ded17dSSimon Glass { 30766ded17dSSimon Glass char *s; 30866ded17dSSimon Glass int bootdelay; 30966ded17dSSimon Glass #ifdef CONFIG_BOOTCOUNT_LIMIT 31066ded17dSSimon Glass unsigned long bootcount = 0; 31166ded17dSSimon Glass unsigned long bootlimit = 0; 31266ded17dSSimon Glass #endif /* CONFIG_BOOTCOUNT_LIMIT */ 31366ded17dSSimon Glass 31466ded17dSSimon Glass #ifdef CONFIG_BOOTCOUNT_LIMIT 31566ded17dSSimon Glass bootcount = bootcount_load(); 31666ded17dSSimon Glass bootcount++; 31766ded17dSSimon Glass bootcount_store(bootcount); 31866ded17dSSimon Glass setenv_ulong("bootcount", bootcount); 31966ded17dSSimon Glass bootlimit = getenv_ulong("bootlimit", 10, 0); 32066ded17dSSimon Glass #endif /* CONFIG_BOOTCOUNT_LIMIT */ 32166ded17dSSimon Glass 32266ded17dSSimon Glass s = getenv("bootdelay"); 32366ded17dSSimon Glass bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; 32466ded17dSSimon Glass 32566ded17dSSimon Glass #ifdef CONFIG_OF_CONTROL 32666ded17dSSimon Glass bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay", 32766ded17dSSimon Glass bootdelay); 32866ded17dSSimon Glass #endif 32966ded17dSSimon Glass 33066ded17dSSimon Glass debug("### main_loop entered: bootdelay=%d\n\n", bootdelay); 33166ded17dSSimon Glass 33266ded17dSSimon Glass #if defined(CONFIG_MENU_SHOW) 33366ded17dSSimon Glass bootdelay = menu_show(bootdelay); 33466ded17dSSimon Glass #endif 335b26440f1SSimon Glass bootretry_init_cmd_timeout(); 33666ded17dSSimon Glass 33766ded17dSSimon Glass #ifdef CONFIG_POST 33866ded17dSSimon Glass if (gd->flags & GD_FLG_POSTFAIL) { 33966ded17dSSimon Glass s = getenv("failbootcmd"); 34066ded17dSSimon Glass } else 34166ded17dSSimon Glass #endif /* CONFIG_POST */ 34266ded17dSSimon Glass #ifdef CONFIG_BOOTCOUNT_LIMIT 34366ded17dSSimon Glass if (bootlimit && (bootcount > bootlimit)) { 34466ded17dSSimon Glass printf("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n", 34566ded17dSSimon Glass (unsigned)bootlimit); 34666ded17dSSimon Glass s = getenv("altbootcmd"); 34766ded17dSSimon Glass } else 34866ded17dSSimon Glass #endif /* CONFIG_BOOTCOUNT_LIMIT */ 34966ded17dSSimon Glass s = getenv("bootcmd"); 35066ded17dSSimon Glass 35166ded17dSSimon Glass process_fdt_options(gd->fdt_blob); 352affb2156SSimon Glass stored_bootdelay = bootdelay; 35366ded17dSSimon Glass 354affb2156SSimon Glass return s; 355affb2156SSimon Glass } 35666ded17dSSimon Glass 357affb2156SSimon Glass void autoboot_command(const char *s) 358affb2156SSimon Glass { 35966ded17dSSimon Glass debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); 36066ded17dSSimon Glass 361affb2156SSimon Glass if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) { 36266ded17dSSimon Glass #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC) 36366ded17dSSimon Glass int prev = disable_ctrlc(1); /* disable Control C checking */ 36466ded17dSSimon Glass #endif 36566ded17dSSimon Glass 36666ded17dSSimon Glass run_command_list(s, -1, 0); 36766ded17dSSimon Glass 36866ded17dSSimon Glass #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC) 36966ded17dSSimon Glass disable_ctrlc(prev); /* restore Control C checking */ 37066ded17dSSimon Glass #endif 37166ded17dSSimon Glass } 37266ded17dSSimon Glass 37366ded17dSSimon Glass #ifdef CONFIG_MENUKEY 37466ded17dSSimon Glass if (menukey == CONFIG_MENUKEY) { 37566ded17dSSimon Glass s = getenv("menucmd"); 37666ded17dSSimon Glass if (s) 37766ded17dSSimon Glass run_command_list(s, -1, 0); 37866ded17dSSimon Glass } 37966ded17dSSimon Glass #endif /* CONFIG_MENUKEY */ 38066ded17dSSimon Glass } 381