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