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> 1266ded17dSSimon Glass #include <fdtdec.h> 1366ded17dSSimon Glass #include <menu.h> 1466ded17dSSimon Glass #include <post.h> 15*8f0b1e24SStefan Roese #include <u-boot/sha256.h> 1666ded17dSSimon Glass 1766ded17dSSimon Glass DECLARE_GLOBAL_DATA_PTR; 1866ded17dSSimon Glass 1966ded17dSSimon Glass #define MAX_DELAY_STOP_STR 32 2066ded17dSSimon Glass 2166ded17dSSimon Glass #ifndef DEBUG_BOOTKEYS 2266ded17dSSimon Glass #define DEBUG_BOOTKEYS 0 2366ded17dSSimon Glass #endif 2466ded17dSSimon Glass #define debug_bootkeys(fmt, args...) \ 2566ded17dSSimon Glass debug_cond(DEBUG_BOOTKEYS, fmt, ##args) 2666ded17dSSimon Glass 27affb2156SSimon Glass /* Stored value of bootdelay, used by autoboot_command() */ 28affb2156SSimon Glass static int stored_bootdelay; 29affb2156SSimon Glass 3066ded17dSSimon Glass #if defined(CONFIG_AUTOBOOT_KEYED) 31*8f0b1e24SStefan Roese #if defined(CONFIG_AUTOBOOT_STOP_STR_SHA256) 32*8f0b1e24SStefan Roese 33*8f0b1e24SStefan Roese /* 34*8f0b1e24SStefan Roese * Use a "constant-length" time compare function for this 35*8f0b1e24SStefan Roese * hash compare: 36*8f0b1e24SStefan Roese * 37*8f0b1e24SStefan Roese * https://crackstation.net/hashing-security.htm 38*8f0b1e24SStefan Roese */ 39*8f0b1e24SStefan Roese static int slow_equals(u8 *a, u8 *b, int len) 40*8f0b1e24SStefan Roese { 41*8f0b1e24SStefan Roese int diff = 0; 42*8f0b1e24SStefan Roese int i; 43*8f0b1e24SStefan Roese 44*8f0b1e24SStefan Roese for (i = 0; i < len; i++) 45*8f0b1e24SStefan Roese diff |= a[i] ^ b[i]; 46*8f0b1e24SStefan Roese 47*8f0b1e24SStefan Roese return diff == 0; 48*8f0b1e24SStefan Roese } 49*8f0b1e24SStefan Roese 50*8f0b1e24SStefan Roese static int passwd_abort(uint64_t etime) 51*8f0b1e24SStefan Roese { 52*8f0b1e24SStefan Roese const char *sha_env_str = getenv("bootstopkeysha256"); 53*8f0b1e24SStefan Roese u8 sha_env[SHA256_SUM_LEN]; 54*8f0b1e24SStefan Roese u8 sha[SHA256_SUM_LEN]; 55*8f0b1e24SStefan Roese char presskey[MAX_DELAY_STOP_STR]; 56*8f0b1e24SStefan Roese const char *algo_name = "sha256"; 57*8f0b1e24SStefan Roese u_int presskey_len = 0; 58*8f0b1e24SStefan Roese int abort = 0; 59*8f0b1e24SStefan Roese int size; 60*8f0b1e24SStefan Roese int ret; 61*8f0b1e24SStefan Roese 62*8f0b1e24SStefan Roese if (sha_env_str == NULL) 63*8f0b1e24SStefan Roese sha_env_str = CONFIG_AUTOBOOT_STOP_STR_SHA256; 64*8f0b1e24SStefan Roese 65*8f0b1e24SStefan Roese /* 66*8f0b1e24SStefan Roese * Generate the binary value from the environment hash value 67*8f0b1e24SStefan Roese * so that we can compare this value with the computed hash 68*8f0b1e24SStefan Roese * from the user input 69*8f0b1e24SStefan Roese */ 70*8f0b1e24SStefan Roese ret = hash_parse_string(algo_name, sha_env_str, sha_env); 71*8f0b1e24SStefan Roese if (ret) { 72*8f0b1e24SStefan Roese printf("Hash %s not supported!\n", algo_name); 73*8f0b1e24SStefan Roese return 0; 74*8f0b1e24SStefan Roese } 75*8f0b1e24SStefan Roese 76*8f0b1e24SStefan Roese /* 77*8f0b1e24SStefan Roese * We don't know how long the stop-string is, so we need to 78*8f0b1e24SStefan Roese * generate the sha256 hash upon each input character and 79*8f0b1e24SStefan Roese * compare the value with the one saved in the environment 80*8f0b1e24SStefan Roese */ 81*8f0b1e24SStefan Roese do { 82*8f0b1e24SStefan Roese if (tstc()) { 83*8f0b1e24SStefan Roese /* Check for input string overflow */ 84*8f0b1e24SStefan Roese if (presskey_len >= MAX_DELAY_STOP_STR) 85*8f0b1e24SStefan Roese return 0; 86*8f0b1e24SStefan Roese 87*8f0b1e24SStefan Roese presskey[presskey_len++] = getc(); 88*8f0b1e24SStefan Roese 89*8f0b1e24SStefan Roese /* Calculate sha256 upon each new char */ 90*8f0b1e24SStefan Roese hash_block(algo_name, (const void *)presskey, 91*8f0b1e24SStefan Roese presskey_len, sha, &size); 92*8f0b1e24SStefan Roese 93*8f0b1e24SStefan Roese /* And check if sha matches saved value in env */ 94*8f0b1e24SStefan Roese if (slow_equals(sha, sha_env, SHA256_SUM_LEN)) 95*8f0b1e24SStefan Roese abort = 1; 96*8f0b1e24SStefan Roese } 97*8f0b1e24SStefan Roese } while (!abort && get_ticks() <= etime); 98*8f0b1e24SStefan Roese 99*8f0b1e24SStefan Roese return abort; 100*8f0b1e24SStefan Roese } 101*8f0b1e24SStefan Roese #else 102*8f0b1e24SStefan Roese static int passwd_abort(uint64_t etime) 10366ded17dSSimon Glass { 10466ded17dSSimon Glass int abort = 0; 10566ded17dSSimon Glass struct { 10666ded17dSSimon Glass char *str; 10766ded17dSSimon Glass u_int len; 10866ded17dSSimon Glass int retry; 10966ded17dSSimon Glass } 11066ded17dSSimon Glass delaykey[] = { 1119e546ee9SJeroen Hofstee { .str = getenv("bootdelaykey"), .retry = 1 }, 1129e546ee9SJeroen Hofstee { .str = getenv("bootstopkey"), .retry = 0 }, 11366ded17dSSimon Glass }; 11466ded17dSSimon Glass 11566ded17dSSimon Glass char presskey[MAX_DELAY_STOP_STR]; 11666ded17dSSimon Glass u_int presskey_len = 0; 11766ded17dSSimon Glass u_int presskey_max = 0; 11866ded17dSSimon Glass u_int i; 11966ded17dSSimon Glass 12066ded17dSSimon Glass # ifdef CONFIG_AUTOBOOT_DELAY_STR 12166ded17dSSimon Glass if (delaykey[0].str == NULL) 12266ded17dSSimon Glass delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR; 12366ded17dSSimon Glass # endif 12466ded17dSSimon Glass # ifdef CONFIG_AUTOBOOT_STOP_STR 1252d908fa0SStefan Roese if (delaykey[1].str == NULL) 1262d908fa0SStefan Roese delaykey[1].str = CONFIG_AUTOBOOT_STOP_STR; 12766ded17dSSimon Glass # endif 12866ded17dSSimon Glass 12966ded17dSSimon Glass for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) { 13066ded17dSSimon Glass delaykey[i].len = delaykey[i].str == NULL ? 13166ded17dSSimon Glass 0 : strlen(delaykey[i].str); 13266ded17dSSimon Glass delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ? 13366ded17dSSimon Glass MAX_DELAY_STOP_STR : delaykey[i].len; 13466ded17dSSimon Glass 13566ded17dSSimon Glass presskey_max = presskey_max > delaykey[i].len ? 13666ded17dSSimon Glass presskey_max : delaykey[i].len; 13766ded17dSSimon Glass 13866ded17dSSimon Glass debug_bootkeys("%s key:<%s>\n", 13966ded17dSSimon Glass delaykey[i].retry ? "delay" : "stop", 14066ded17dSSimon Glass delaykey[i].str ? delaykey[i].str : "NULL"); 14166ded17dSSimon Glass } 14266ded17dSSimon Glass 14366ded17dSSimon Glass /* In order to keep up with incoming data, check timeout only 14466ded17dSSimon Glass * when catch up. 14566ded17dSSimon Glass */ 14666ded17dSSimon Glass do { 14766ded17dSSimon Glass if (tstc()) { 14866ded17dSSimon Glass if (presskey_len < presskey_max) { 14966ded17dSSimon Glass presskey[presskey_len++] = getc(); 15066ded17dSSimon Glass } else { 15166ded17dSSimon Glass for (i = 0; i < presskey_max - 1; i++) 15266ded17dSSimon Glass presskey[i] = presskey[i + 1]; 15366ded17dSSimon Glass 15466ded17dSSimon Glass presskey[i] = getc(); 15566ded17dSSimon Glass } 15666ded17dSSimon Glass } 15766ded17dSSimon Glass 15866ded17dSSimon Glass for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) { 15966ded17dSSimon Glass if (delaykey[i].len > 0 && 16066ded17dSSimon Glass presskey_len >= delaykey[i].len && 16166ded17dSSimon Glass memcmp(presskey + presskey_len - 16266ded17dSSimon Glass delaykey[i].len, delaykey[i].str, 16366ded17dSSimon Glass delaykey[i].len) == 0) { 16466ded17dSSimon Glass debug_bootkeys("got %skey\n", 16566ded17dSSimon Glass delaykey[i].retry ? "delay" : 16666ded17dSSimon Glass "stop"); 16766ded17dSSimon Glass 16866ded17dSSimon Glass /* don't retry auto boot */ 16966ded17dSSimon Glass if (!delaykey[i].retry) 17066ded17dSSimon Glass bootretry_dont_retry(); 17166ded17dSSimon Glass abort = 1; 17266ded17dSSimon Glass } 17366ded17dSSimon Glass } 17466ded17dSSimon Glass } while (!abort && get_ticks() <= etime); 17566ded17dSSimon Glass 176*8f0b1e24SStefan Roese return abort; 177*8f0b1e24SStefan Roese } 178*8f0b1e24SStefan Roese #endif 179*8f0b1e24SStefan Roese 180*8f0b1e24SStefan Roese /*************************************************************************** 181*8f0b1e24SStefan Roese * Watch for 'delay' seconds for autoboot stop or autoboot delay string. 182*8f0b1e24SStefan Roese * returns: 0 - no key string, allow autoboot 1 - got key string, abort 183*8f0b1e24SStefan Roese */ 184*8f0b1e24SStefan Roese static int abortboot_keyed(int bootdelay) 185*8f0b1e24SStefan Roese { 186*8f0b1e24SStefan Roese int abort; 187*8f0b1e24SStefan Roese uint64_t etime = endtick(bootdelay); 188*8f0b1e24SStefan Roese 189*8f0b1e24SStefan Roese #ifndef CONFIG_ZERO_BOOTDELAY_CHECK 190*8f0b1e24SStefan Roese if (bootdelay == 0) 191*8f0b1e24SStefan Roese return 0; 192*8f0b1e24SStefan Roese #endif 193*8f0b1e24SStefan Roese 194*8f0b1e24SStefan Roese # ifdef CONFIG_AUTOBOOT_PROMPT 195*8f0b1e24SStefan Roese /* 196*8f0b1e24SStefan Roese * CONFIG_AUTOBOOT_PROMPT includes the %d for all boards. 197*8f0b1e24SStefan Roese * To print the bootdelay value upon bootup. 198*8f0b1e24SStefan Roese */ 199*8f0b1e24SStefan Roese printf(CONFIG_AUTOBOOT_PROMPT, bootdelay); 200*8f0b1e24SStefan Roese # endif 201*8f0b1e24SStefan Roese 202*8f0b1e24SStefan Roese abort = passwd_abort(etime); 20366ded17dSSimon Glass if (!abort) 20466ded17dSSimon Glass debug_bootkeys("key timeout\n"); 20566ded17dSSimon Glass 20666ded17dSSimon Glass #ifdef CONFIG_SILENT_CONSOLE 20766ded17dSSimon Glass if (abort) 20866ded17dSSimon Glass gd->flags &= ~GD_FLG_SILENT; 20966ded17dSSimon Glass #endif 21066ded17dSSimon Glass 21166ded17dSSimon Glass return abort; 21266ded17dSSimon Glass } 21366ded17dSSimon Glass 21466ded17dSSimon Glass # else /* !defined(CONFIG_AUTOBOOT_KEYED) */ 21566ded17dSSimon Glass 21666ded17dSSimon Glass #ifdef CONFIG_MENUKEY 21766ded17dSSimon Glass static int menukey; 21866ded17dSSimon Glass #endif 21966ded17dSSimon Glass 22066ded17dSSimon Glass static int abortboot_normal(int bootdelay) 22166ded17dSSimon Glass { 22266ded17dSSimon Glass int abort = 0; 22366ded17dSSimon Glass unsigned long ts; 22466ded17dSSimon Glass 22566ded17dSSimon Glass #ifdef CONFIG_MENUPROMPT 22666ded17dSSimon Glass printf(CONFIG_MENUPROMPT); 22766ded17dSSimon Glass #else 22866ded17dSSimon Glass if (bootdelay >= 0) 22966ded17dSSimon Glass printf("Hit any key to stop autoboot: %2d ", bootdelay); 23066ded17dSSimon Glass #endif 23166ded17dSSimon Glass 23266ded17dSSimon Glass #if defined CONFIG_ZERO_BOOTDELAY_CHECK 23366ded17dSSimon Glass /* 23466ded17dSSimon Glass * Check if key already pressed 23566ded17dSSimon Glass * Don't check if bootdelay < 0 23666ded17dSSimon Glass */ 23766ded17dSSimon Glass if (bootdelay >= 0) { 23866ded17dSSimon Glass if (tstc()) { /* we got a key press */ 23966ded17dSSimon Glass (void) getc(); /* consume input */ 24066ded17dSSimon Glass puts("\b\b\b 0"); 24166ded17dSSimon Glass abort = 1; /* don't auto boot */ 24266ded17dSSimon Glass } 24366ded17dSSimon Glass } 24466ded17dSSimon Glass #endif 24566ded17dSSimon Glass 24666ded17dSSimon Glass while ((bootdelay > 0) && (!abort)) { 24766ded17dSSimon Glass --bootdelay; 24866ded17dSSimon Glass /* delay 1000 ms */ 24966ded17dSSimon Glass ts = get_timer(0); 25066ded17dSSimon Glass do { 25166ded17dSSimon Glass if (tstc()) { /* we got a key press */ 25266ded17dSSimon Glass abort = 1; /* don't auto boot */ 25366ded17dSSimon Glass bootdelay = 0; /* no more delay */ 25466ded17dSSimon Glass # ifdef CONFIG_MENUKEY 25566ded17dSSimon Glass menukey = getc(); 25666ded17dSSimon Glass # else 25766ded17dSSimon Glass (void) getc(); /* consume input */ 25866ded17dSSimon Glass # endif 25966ded17dSSimon Glass break; 26066ded17dSSimon Glass } 26166ded17dSSimon Glass udelay(10000); 26266ded17dSSimon Glass } while (!abort && get_timer(ts) < 1000); 26366ded17dSSimon Glass 26466ded17dSSimon Glass printf("\b\b\b%2d ", bootdelay); 26566ded17dSSimon Glass } 26666ded17dSSimon Glass 26766ded17dSSimon Glass putc('\n'); 26866ded17dSSimon Glass 26966ded17dSSimon Glass #ifdef CONFIG_SILENT_CONSOLE 27066ded17dSSimon Glass if (abort) 27166ded17dSSimon Glass gd->flags &= ~GD_FLG_SILENT; 27266ded17dSSimon Glass #endif 27366ded17dSSimon Glass 27466ded17dSSimon Glass return abort; 27566ded17dSSimon Glass } 27666ded17dSSimon Glass # endif /* CONFIG_AUTOBOOT_KEYED */ 27766ded17dSSimon Glass 27866ded17dSSimon Glass static int abortboot(int bootdelay) 27966ded17dSSimon Glass { 28066ded17dSSimon Glass #ifdef CONFIG_AUTOBOOT_KEYED 28166ded17dSSimon Glass return abortboot_keyed(bootdelay); 28266ded17dSSimon Glass #else 28366ded17dSSimon Glass return abortboot_normal(bootdelay); 28466ded17dSSimon Glass #endif 28566ded17dSSimon Glass } 28666ded17dSSimon Glass 28766ded17dSSimon Glass static void process_fdt_options(const void *blob) 28866ded17dSSimon Glass { 289affb2156SSimon Glass #if defined(CONFIG_OF_CONTROL) 29066ded17dSSimon Glass ulong addr; 29166ded17dSSimon Glass 29266ded17dSSimon Glass /* Add an env variable to point to a kernel payload, if available */ 29366ded17dSSimon Glass addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0); 29466ded17dSSimon Glass if (addr) 29566ded17dSSimon Glass setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); 29666ded17dSSimon Glass 29766ded17dSSimon Glass /* Add an env variable to point to a root disk, if available */ 29866ded17dSSimon Glass addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0); 29966ded17dSSimon Glass if (addr) 30066ded17dSSimon Glass setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); 30166ded17dSSimon Glass #endif /* CONFIG_OF_CONTROL */ 302affb2156SSimon Glass } 30366ded17dSSimon Glass 304affb2156SSimon Glass const char *bootdelay_process(void) 30566ded17dSSimon Glass { 30666ded17dSSimon Glass char *s; 30766ded17dSSimon Glass int bootdelay; 30866ded17dSSimon Glass #ifdef CONFIG_BOOTCOUNT_LIMIT 30966ded17dSSimon Glass unsigned long bootcount = 0; 31066ded17dSSimon Glass unsigned long bootlimit = 0; 31166ded17dSSimon Glass #endif /* CONFIG_BOOTCOUNT_LIMIT */ 31266ded17dSSimon Glass 31366ded17dSSimon Glass #ifdef CONFIG_BOOTCOUNT_LIMIT 31466ded17dSSimon Glass bootcount = bootcount_load(); 31566ded17dSSimon Glass bootcount++; 31666ded17dSSimon Glass bootcount_store(bootcount); 31766ded17dSSimon Glass setenv_ulong("bootcount", bootcount); 31866ded17dSSimon Glass bootlimit = getenv_ulong("bootlimit", 10, 0); 31966ded17dSSimon Glass #endif /* CONFIG_BOOTCOUNT_LIMIT */ 32066ded17dSSimon Glass 32166ded17dSSimon Glass s = getenv("bootdelay"); 32266ded17dSSimon Glass bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; 32366ded17dSSimon Glass 32466ded17dSSimon Glass #ifdef CONFIG_OF_CONTROL 32566ded17dSSimon Glass bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay", 32666ded17dSSimon Glass bootdelay); 32766ded17dSSimon Glass #endif 32866ded17dSSimon Glass 32966ded17dSSimon Glass debug("### main_loop entered: bootdelay=%d\n\n", bootdelay); 33066ded17dSSimon Glass 33166ded17dSSimon Glass #if defined(CONFIG_MENU_SHOW) 33266ded17dSSimon Glass bootdelay = menu_show(bootdelay); 33366ded17dSSimon Glass #endif 334b26440f1SSimon Glass bootretry_init_cmd_timeout(); 33566ded17dSSimon Glass 33666ded17dSSimon Glass #ifdef CONFIG_POST 33766ded17dSSimon Glass if (gd->flags & GD_FLG_POSTFAIL) { 33866ded17dSSimon Glass s = getenv("failbootcmd"); 33966ded17dSSimon Glass } else 34066ded17dSSimon Glass #endif /* CONFIG_POST */ 34166ded17dSSimon Glass #ifdef CONFIG_BOOTCOUNT_LIMIT 34266ded17dSSimon Glass if (bootlimit && (bootcount > bootlimit)) { 34366ded17dSSimon Glass printf("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n", 34466ded17dSSimon Glass (unsigned)bootlimit); 34566ded17dSSimon Glass s = getenv("altbootcmd"); 34666ded17dSSimon Glass } else 34766ded17dSSimon Glass #endif /* CONFIG_BOOTCOUNT_LIMIT */ 34866ded17dSSimon Glass s = getenv("bootcmd"); 34966ded17dSSimon Glass 35066ded17dSSimon Glass process_fdt_options(gd->fdt_blob); 351affb2156SSimon Glass stored_bootdelay = bootdelay; 35266ded17dSSimon Glass 353affb2156SSimon Glass return s; 354affb2156SSimon Glass } 35566ded17dSSimon Glass 356affb2156SSimon Glass void autoboot_command(const char *s) 357affb2156SSimon Glass { 35866ded17dSSimon Glass debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); 35966ded17dSSimon Glass 360affb2156SSimon Glass if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) { 36166ded17dSSimon Glass #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC) 36266ded17dSSimon Glass int prev = disable_ctrlc(1); /* disable Control C checking */ 36366ded17dSSimon Glass #endif 36466ded17dSSimon Glass 36566ded17dSSimon Glass run_command_list(s, -1, 0); 36666ded17dSSimon Glass 36766ded17dSSimon Glass #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC) 36866ded17dSSimon Glass disable_ctrlc(prev); /* restore Control C checking */ 36966ded17dSSimon Glass #endif 37066ded17dSSimon Glass } 37166ded17dSSimon Glass 37266ded17dSSimon Glass #ifdef CONFIG_MENUKEY 37366ded17dSSimon Glass if (menukey == CONFIG_MENUKEY) { 37466ded17dSSimon Glass s = getenv("menucmd"); 37566ded17dSSimon Glass if (s) 37666ded17dSSimon Glass run_command_list(s, -1, 0); 37766ded17dSSimon Glass } 37866ded17dSSimon Glass #endif /* CONFIG_MENUKEY */ 37966ded17dSSimon Glass } 380