xref: /openbmc/u-boot/common/autoboot.c (revision 8f0b1e24)
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