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