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 */ 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 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 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 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) 281*018f5303SSimon 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) 286*018f5303SSimon 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 290affb2156SSimon Glass const char *bootdelay_process(void) 29166ded17dSSimon Glass { 29266ded17dSSimon Glass char *s; 29366ded17dSSimon Glass int bootdelay; 29466ded17dSSimon Glass #ifdef CONFIG_BOOTCOUNT_LIMIT 29566ded17dSSimon Glass unsigned long bootcount = 0; 29666ded17dSSimon Glass unsigned long bootlimit = 0; 29766ded17dSSimon Glass #endif /* CONFIG_BOOTCOUNT_LIMIT */ 29866ded17dSSimon Glass 29966ded17dSSimon Glass #ifdef CONFIG_BOOTCOUNT_LIMIT 30066ded17dSSimon Glass bootcount = bootcount_load(); 30166ded17dSSimon Glass bootcount++; 30266ded17dSSimon Glass bootcount_store(bootcount); 303*018f5303SSimon Glass env_set_ulong("bootcount", bootcount); 30466ded17dSSimon Glass bootlimit = getenv_ulong("bootlimit", 10, 0); 30566ded17dSSimon Glass #endif /* CONFIG_BOOTCOUNT_LIMIT */ 30666ded17dSSimon Glass 30766ded17dSSimon Glass s = getenv("bootdelay"); 30866ded17dSSimon Glass bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; 30966ded17dSSimon Glass 31066ded17dSSimon Glass #ifdef CONFIG_OF_CONTROL 31166ded17dSSimon Glass bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay", 31266ded17dSSimon Glass bootdelay); 31366ded17dSSimon Glass #endif 31466ded17dSSimon Glass 31566ded17dSSimon Glass debug("### main_loop entered: bootdelay=%d\n\n", bootdelay); 31666ded17dSSimon Glass 31766ded17dSSimon Glass #if defined(CONFIG_MENU_SHOW) 31866ded17dSSimon Glass bootdelay = menu_show(bootdelay); 31966ded17dSSimon Glass #endif 320b26440f1SSimon Glass bootretry_init_cmd_timeout(); 32166ded17dSSimon Glass 32266ded17dSSimon Glass #ifdef CONFIG_POST 32366ded17dSSimon Glass if (gd->flags & GD_FLG_POSTFAIL) { 32466ded17dSSimon Glass s = getenv("failbootcmd"); 32566ded17dSSimon Glass } else 32666ded17dSSimon Glass #endif /* CONFIG_POST */ 32766ded17dSSimon Glass #ifdef CONFIG_BOOTCOUNT_LIMIT 32866ded17dSSimon Glass if (bootlimit && (bootcount > bootlimit)) { 32966ded17dSSimon Glass printf("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n", 33066ded17dSSimon Glass (unsigned)bootlimit); 33166ded17dSSimon Glass s = getenv("altbootcmd"); 33266ded17dSSimon Glass } else 33366ded17dSSimon Glass #endif /* CONFIG_BOOTCOUNT_LIMIT */ 33466ded17dSSimon Glass s = getenv("bootcmd"); 33566ded17dSSimon Glass 33666ded17dSSimon Glass process_fdt_options(gd->fdt_blob); 337affb2156SSimon Glass stored_bootdelay = bootdelay; 33866ded17dSSimon Glass 339affb2156SSimon Glass return s; 340affb2156SSimon Glass } 34166ded17dSSimon Glass 342affb2156SSimon Glass void autoboot_command(const char *s) 343affb2156SSimon Glass { 34466ded17dSSimon Glass debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); 34566ded17dSSimon Glass 346affb2156SSimon Glass if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) { 34766ded17dSSimon Glass #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC) 34866ded17dSSimon Glass int prev = disable_ctrlc(1); /* disable Control C checking */ 34966ded17dSSimon Glass #endif 35066ded17dSSimon Glass 35166ded17dSSimon Glass run_command_list(s, -1, 0); 35266ded17dSSimon Glass 35366ded17dSSimon Glass #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC) 35466ded17dSSimon Glass disable_ctrlc(prev); /* restore Control C checking */ 35566ded17dSSimon Glass #endif 35666ded17dSSimon Glass } 35766ded17dSSimon Glass 35866ded17dSSimon Glass #ifdef CONFIG_MENUKEY 35966ded17dSSimon Glass if (menukey == CONFIG_MENUKEY) { 36066ded17dSSimon Glass s = getenv("menucmd"); 36166ded17dSSimon Glass if (s) 36266ded17dSSimon Glass run_command_list(s, -1, 0); 36366ded17dSSimon Glass } 36466ded17dSSimon Glass #endif /* CONFIG_MENUKEY */ 36566ded17dSSimon Glass } 366