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> 90098e179SSimon Glass #include <bootretry.h> 1066ded17dSSimon Glass #include <cli.h> 1166ded17dSSimon Glass #include <fdtdec.h> 1266ded17dSSimon Glass #include <menu.h> 1366ded17dSSimon Glass #include <post.h> 1466ded17dSSimon Glass 1566ded17dSSimon Glass DECLARE_GLOBAL_DATA_PTR; 1666ded17dSSimon Glass 1766ded17dSSimon Glass #define MAX_DELAY_STOP_STR 32 1866ded17dSSimon Glass 1966ded17dSSimon Glass #ifndef DEBUG_BOOTKEYS 2066ded17dSSimon Glass #define DEBUG_BOOTKEYS 0 2166ded17dSSimon Glass #endif 2266ded17dSSimon Glass #define debug_bootkeys(fmt, args...) \ 2366ded17dSSimon Glass debug_cond(DEBUG_BOOTKEYS, fmt, ##args) 2466ded17dSSimon Glass 25affb2156SSimon Glass /* Stored value of bootdelay, used by autoboot_command() */ 26affb2156SSimon Glass static int stored_bootdelay; 27affb2156SSimon Glass 2866ded17dSSimon Glass /*************************************************************************** 2966ded17dSSimon Glass * Watch for 'delay' seconds for autoboot stop or autoboot delay string. 3066ded17dSSimon Glass * returns: 0 - no key string, allow autoboot 1 - got key string, abort 3166ded17dSSimon Glass */ 3266ded17dSSimon Glass # if defined(CONFIG_AUTOBOOT_KEYED) 3366ded17dSSimon Glass static int abortboot_keyed(int bootdelay) 3466ded17dSSimon Glass { 3566ded17dSSimon Glass int abort = 0; 3666ded17dSSimon Glass uint64_t etime = endtick(bootdelay); 3766ded17dSSimon Glass struct { 3866ded17dSSimon Glass char *str; 3966ded17dSSimon Glass u_int len; 4066ded17dSSimon Glass int retry; 4166ded17dSSimon Glass } 4266ded17dSSimon Glass delaykey[] = { 43*9e546ee9SJeroen Hofstee { .str = getenv("bootdelaykey"), .retry = 1 }, 44*9e546ee9SJeroen Hofstee { .str = getenv("bootdelaykey2"), .retry = 1 }, 45*9e546ee9SJeroen Hofstee { .str = getenv("bootstopkey"), .retry = 0 }, 46*9e546ee9SJeroen Hofstee { .str = getenv("bootstopkey2"), .retry = 0 }, 4766ded17dSSimon Glass }; 4866ded17dSSimon Glass 4966ded17dSSimon Glass char presskey[MAX_DELAY_STOP_STR]; 5066ded17dSSimon Glass u_int presskey_len = 0; 5166ded17dSSimon Glass u_int presskey_max = 0; 5266ded17dSSimon Glass u_int i; 5366ded17dSSimon Glass 5466ded17dSSimon Glass #ifndef CONFIG_ZERO_BOOTDELAY_CHECK 5566ded17dSSimon Glass if (bootdelay == 0) 5666ded17dSSimon Glass return 0; 5766ded17dSSimon Glass #endif 5866ded17dSSimon Glass 5966ded17dSSimon Glass # ifdef CONFIG_AUTOBOOT_PROMPT 6066ded17dSSimon Glass printf(CONFIG_AUTOBOOT_PROMPT); 6166ded17dSSimon Glass # endif 6266ded17dSSimon Glass 6366ded17dSSimon Glass # ifdef CONFIG_AUTOBOOT_DELAY_STR 6466ded17dSSimon Glass if (delaykey[0].str == NULL) 6566ded17dSSimon Glass delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR; 6666ded17dSSimon Glass # endif 6766ded17dSSimon Glass # ifdef CONFIG_AUTOBOOT_DELAY_STR2 6866ded17dSSimon Glass if (delaykey[1].str == NULL) 6966ded17dSSimon Glass delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2; 7066ded17dSSimon Glass # endif 7166ded17dSSimon Glass # ifdef CONFIG_AUTOBOOT_STOP_STR 7266ded17dSSimon Glass if (delaykey[2].str == NULL) 7366ded17dSSimon Glass delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR; 7466ded17dSSimon Glass # endif 7566ded17dSSimon Glass # ifdef CONFIG_AUTOBOOT_STOP_STR2 7666ded17dSSimon Glass if (delaykey[3].str == NULL) 7766ded17dSSimon Glass delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2; 7866ded17dSSimon Glass # endif 7966ded17dSSimon Glass 8066ded17dSSimon Glass for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) { 8166ded17dSSimon Glass delaykey[i].len = delaykey[i].str == NULL ? 8266ded17dSSimon Glass 0 : strlen(delaykey[i].str); 8366ded17dSSimon Glass delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ? 8466ded17dSSimon Glass MAX_DELAY_STOP_STR : delaykey[i].len; 8566ded17dSSimon Glass 8666ded17dSSimon Glass presskey_max = presskey_max > delaykey[i].len ? 8766ded17dSSimon Glass presskey_max : delaykey[i].len; 8866ded17dSSimon Glass 8966ded17dSSimon Glass debug_bootkeys("%s key:<%s>\n", 9066ded17dSSimon Glass delaykey[i].retry ? "delay" : "stop", 9166ded17dSSimon Glass delaykey[i].str ? delaykey[i].str : "NULL"); 9266ded17dSSimon Glass } 9366ded17dSSimon Glass 9466ded17dSSimon Glass /* In order to keep up with incoming data, check timeout only 9566ded17dSSimon Glass * when catch up. 9666ded17dSSimon Glass */ 9766ded17dSSimon Glass do { 9866ded17dSSimon Glass if (tstc()) { 9966ded17dSSimon Glass if (presskey_len < presskey_max) { 10066ded17dSSimon Glass presskey[presskey_len++] = getc(); 10166ded17dSSimon Glass } else { 10266ded17dSSimon Glass for (i = 0; i < presskey_max - 1; i++) 10366ded17dSSimon Glass presskey[i] = presskey[i + 1]; 10466ded17dSSimon Glass 10566ded17dSSimon Glass presskey[i] = getc(); 10666ded17dSSimon Glass } 10766ded17dSSimon Glass } 10866ded17dSSimon Glass 10966ded17dSSimon Glass for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) { 11066ded17dSSimon Glass if (delaykey[i].len > 0 && 11166ded17dSSimon Glass presskey_len >= delaykey[i].len && 11266ded17dSSimon Glass memcmp(presskey + presskey_len - 11366ded17dSSimon Glass delaykey[i].len, delaykey[i].str, 11466ded17dSSimon Glass delaykey[i].len) == 0) { 11566ded17dSSimon Glass debug_bootkeys("got %skey\n", 11666ded17dSSimon Glass delaykey[i].retry ? "delay" : 11766ded17dSSimon Glass "stop"); 11866ded17dSSimon Glass 11966ded17dSSimon Glass /* don't retry auto boot */ 12066ded17dSSimon Glass if (!delaykey[i].retry) 12166ded17dSSimon Glass bootretry_dont_retry(); 12266ded17dSSimon Glass abort = 1; 12366ded17dSSimon Glass } 12466ded17dSSimon Glass } 12566ded17dSSimon Glass } while (!abort && get_ticks() <= etime); 12666ded17dSSimon Glass 12766ded17dSSimon Glass if (!abort) 12866ded17dSSimon Glass debug_bootkeys("key timeout\n"); 12966ded17dSSimon Glass 13066ded17dSSimon Glass #ifdef CONFIG_SILENT_CONSOLE 13166ded17dSSimon Glass if (abort) 13266ded17dSSimon Glass gd->flags &= ~GD_FLG_SILENT; 13366ded17dSSimon Glass #endif 13466ded17dSSimon Glass 13566ded17dSSimon Glass return abort; 13666ded17dSSimon Glass } 13766ded17dSSimon Glass 13866ded17dSSimon Glass # else /* !defined(CONFIG_AUTOBOOT_KEYED) */ 13966ded17dSSimon Glass 14066ded17dSSimon Glass #ifdef CONFIG_MENUKEY 14166ded17dSSimon Glass static int menukey; 14266ded17dSSimon Glass #endif 14366ded17dSSimon Glass 14466ded17dSSimon Glass static int abortboot_normal(int bootdelay) 14566ded17dSSimon Glass { 14666ded17dSSimon Glass int abort = 0; 14766ded17dSSimon Glass unsigned long ts; 14866ded17dSSimon Glass 14966ded17dSSimon Glass #ifdef CONFIG_MENUPROMPT 15066ded17dSSimon Glass printf(CONFIG_MENUPROMPT); 15166ded17dSSimon Glass #else 15266ded17dSSimon Glass if (bootdelay >= 0) 15366ded17dSSimon Glass printf("Hit any key to stop autoboot: %2d ", bootdelay); 15466ded17dSSimon Glass #endif 15566ded17dSSimon Glass 15666ded17dSSimon Glass #if defined CONFIG_ZERO_BOOTDELAY_CHECK 15766ded17dSSimon Glass /* 15866ded17dSSimon Glass * Check if key already pressed 15966ded17dSSimon Glass * Don't check if bootdelay < 0 16066ded17dSSimon Glass */ 16166ded17dSSimon Glass if (bootdelay >= 0) { 16266ded17dSSimon Glass if (tstc()) { /* we got a key press */ 16366ded17dSSimon Glass (void) getc(); /* consume input */ 16466ded17dSSimon Glass puts("\b\b\b 0"); 16566ded17dSSimon Glass abort = 1; /* don't auto boot */ 16666ded17dSSimon Glass } 16766ded17dSSimon Glass } 16866ded17dSSimon Glass #endif 16966ded17dSSimon Glass 17066ded17dSSimon Glass while ((bootdelay > 0) && (!abort)) { 17166ded17dSSimon Glass --bootdelay; 17266ded17dSSimon Glass /* delay 1000 ms */ 17366ded17dSSimon Glass ts = get_timer(0); 17466ded17dSSimon Glass do { 17566ded17dSSimon Glass if (tstc()) { /* we got a key press */ 17666ded17dSSimon Glass abort = 1; /* don't auto boot */ 17766ded17dSSimon Glass bootdelay = 0; /* no more delay */ 17866ded17dSSimon Glass # ifdef CONFIG_MENUKEY 17966ded17dSSimon Glass menukey = getc(); 18066ded17dSSimon Glass # else 18166ded17dSSimon Glass (void) getc(); /* consume input */ 18266ded17dSSimon Glass # endif 18366ded17dSSimon Glass break; 18466ded17dSSimon Glass } 18566ded17dSSimon Glass udelay(10000); 18666ded17dSSimon Glass } while (!abort && get_timer(ts) < 1000); 18766ded17dSSimon Glass 18866ded17dSSimon Glass printf("\b\b\b%2d ", bootdelay); 18966ded17dSSimon Glass } 19066ded17dSSimon Glass 19166ded17dSSimon Glass putc('\n'); 19266ded17dSSimon Glass 19366ded17dSSimon Glass #ifdef CONFIG_SILENT_CONSOLE 19466ded17dSSimon Glass if (abort) 19566ded17dSSimon Glass gd->flags &= ~GD_FLG_SILENT; 19666ded17dSSimon Glass #endif 19766ded17dSSimon Glass 19866ded17dSSimon Glass return abort; 19966ded17dSSimon Glass } 20066ded17dSSimon Glass # endif /* CONFIG_AUTOBOOT_KEYED */ 20166ded17dSSimon Glass 20266ded17dSSimon Glass static int abortboot(int bootdelay) 20366ded17dSSimon Glass { 20466ded17dSSimon Glass #ifdef CONFIG_AUTOBOOT_KEYED 20566ded17dSSimon Glass return abortboot_keyed(bootdelay); 20666ded17dSSimon Glass #else 20766ded17dSSimon Glass return abortboot_normal(bootdelay); 20866ded17dSSimon Glass #endif 20966ded17dSSimon Glass } 21066ded17dSSimon Glass 21166ded17dSSimon Glass static void process_fdt_options(const void *blob) 21266ded17dSSimon Glass { 213affb2156SSimon Glass #if defined(CONFIG_OF_CONTROL) 21466ded17dSSimon Glass ulong addr; 21566ded17dSSimon Glass 21666ded17dSSimon Glass /* Add an env variable to point to a kernel payload, if available */ 21766ded17dSSimon Glass addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0); 21866ded17dSSimon Glass if (addr) 21966ded17dSSimon Glass setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); 22066ded17dSSimon Glass 22166ded17dSSimon Glass /* Add an env variable to point to a root disk, if available */ 22266ded17dSSimon Glass addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0); 22366ded17dSSimon Glass if (addr) 22466ded17dSSimon Glass setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); 22566ded17dSSimon Glass #endif /* CONFIG_OF_CONTROL */ 226affb2156SSimon Glass } 22766ded17dSSimon Glass 228affb2156SSimon Glass const char *bootdelay_process(void) 22966ded17dSSimon Glass { 23066ded17dSSimon Glass char *s; 23166ded17dSSimon Glass int bootdelay; 23266ded17dSSimon Glass #ifdef CONFIG_BOOTCOUNT_LIMIT 23366ded17dSSimon Glass unsigned long bootcount = 0; 23466ded17dSSimon Glass unsigned long bootlimit = 0; 23566ded17dSSimon Glass #endif /* CONFIG_BOOTCOUNT_LIMIT */ 23666ded17dSSimon Glass 23766ded17dSSimon Glass #ifdef CONFIG_BOOTCOUNT_LIMIT 23866ded17dSSimon Glass bootcount = bootcount_load(); 23966ded17dSSimon Glass bootcount++; 24066ded17dSSimon Glass bootcount_store(bootcount); 24166ded17dSSimon Glass setenv_ulong("bootcount", bootcount); 24266ded17dSSimon Glass bootlimit = getenv_ulong("bootlimit", 10, 0); 24366ded17dSSimon Glass #endif /* CONFIG_BOOTCOUNT_LIMIT */ 24466ded17dSSimon Glass 24566ded17dSSimon Glass s = getenv("bootdelay"); 24666ded17dSSimon Glass bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; 24766ded17dSSimon Glass 24866ded17dSSimon Glass #ifdef CONFIG_OF_CONTROL 24966ded17dSSimon Glass bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay", 25066ded17dSSimon Glass bootdelay); 25166ded17dSSimon Glass #endif 25266ded17dSSimon Glass 25366ded17dSSimon Glass debug("### main_loop entered: bootdelay=%d\n\n", bootdelay); 25466ded17dSSimon Glass 25566ded17dSSimon Glass #if defined(CONFIG_MENU_SHOW) 25666ded17dSSimon Glass bootdelay = menu_show(bootdelay); 25766ded17dSSimon Glass #endif 258b26440f1SSimon Glass bootretry_init_cmd_timeout(); 25966ded17dSSimon Glass 26066ded17dSSimon Glass #ifdef CONFIG_POST 26166ded17dSSimon Glass if (gd->flags & GD_FLG_POSTFAIL) { 26266ded17dSSimon Glass s = getenv("failbootcmd"); 26366ded17dSSimon Glass } else 26466ded17dSSimon Glass #endif /* CONFIG_POST */ 26566ded17dSSimon Glass #ifdef CONFIG_BOOTCOUNT_LIMIT 26666ded17dSSimon Glass if (bootlimit && (bootcount > bootlimit)) { 26766ded17dSSimon Glass printf("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n", 26866ded17dSSimon Glass (unsigned)bootlimit); 26966ded17dSSimon Glass s = getenv("altbootcmd"); 27066ded17dSSimon Glass } else 27166ded17dSSimon Glass #endif /* CONFIG_BOOTCOUNT_LIMIT */ 27266ded17dSSimon Glass s = getenv("bootcmd"); 27366ded17dSSimon Glass 27466ded17dSSimon Glass process_fdt_options(gd->fdt_blob); 275affb2156SSimon Glass stored_bootdelay = bootdelay; 27666ded17dSSimon Glass 277affb2156SSimon Glass return s; 278affb2156SSimon Glass } 27966ded17dSSimon Glass 280affb2156SSimon Glass void autoboot_command(const char *s) 281affb2156SSimon Glass { 28266ded17dSSimon Glass debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); 28366ded17dSSimon Glass 284affb2156SSimon Glass if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) { 28566ded17dSSimon Glass #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC) 28666ded17dSSimon Glass int prev = disable_ctrlc(1); /* disable Control C checking */ 28766ded17dSSimon Glass #endif 28866ded17dSSimon Glass 28966ded17dSSimon Glass run_command_list(s, -1, 0); 29066ded17dSSimon Glass 29166ded17dSSimon Glass #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC) 29266ded17dSSimon Glass disable_ctrlc(prev); /* restore Control C checking */ 29366ded17dSSimon Glass #endif 29466ded17dSSimon Glass } 29566ded17dSSimon Glass 29666ded17dSSimon Glass #ifdef CONFIG_MENUKEY 29766ded17dSSimon Glass if (menukey == CONFIG_MENUKEY) { 29866ded17dSSimon Glass s = getenv("menucmd"); 29966ded17dSSimon Glass if (s) 30066ded17dSSimon Glass run_command_list(s, -1, 0); 30166ded17dSSimon Glass } 30266ded17dSSimon Glass #endif /* CONFIG_MENUKEY */ 30366ded17dSSimon Glass } 304