xref: /OK3568_Linux_fs/u-boot/common/autoboot.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2000
3*4882a593Smuzhiyun  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <autoboot.h>
10*4882a593Smuzhiyun #include <bootretry.h>
11*4882a593Smuzhiyun #include <cli.h>
12*4882a593Smuzhiyun #include <console.h>
13*4882a593Smuzhiyun #include <fdtdec.h>
14*4882a593Smuzhiyun #include <menu.h>
15*4882a593Smuzhiyun #include <post.h>
16*4882a593Smuzhiyun #include <u-boot/sha256.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define MAX_DELAY_STOP_STR 32
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #ifndef DEBUG_BOOTKEYS
23*4882a593Smuzhiyun #define DEBUG_BOOTKEYS 0
24*4882a593Smuzhiyun #endif
25*4882a593Smuzhiyun #define debug_bootkeys(fmt, args...)		\
26*4882a593Smuzhiyun 	debug_cond(DEBUG_BOOTKEYS, fmt, ##args)
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /* Stored value of bootdelay, used by autoboot_command() */
29*4882a593Smuzhiyun static int stored_bootdelay;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #if defined(CONFIG_AUTOBOOT_KEYED)
32*4882a593Smuzhiyun #if defined(CONFIG_AUTOBOOT_STOP_STR_SHA256)
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun /*
35*4882a593Smuzhiyun  * Use a "constant-length" time compare function for this
36*4882a593Smuzhiyun  * hash compare:
37*4882a593Smuzhiyun  *
38*4882a593Smuzhiyun  * https://crackstation.net/hashing-security.htm
39*4882a593Smuzhiyun  */
slow_equals(u8 * a,u8 * b,int len)40*4882a593Smuzhiyun static int slow_equals(u8 *a, u8 *b, int len)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	int diff = 0;
43*4882a593Smuzhiyun 	int i;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	for (i = 0; i < len; i++)
46*4882a593Smuzhiyun 		diff |= a[i] ^ b[i];
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	return diff == 0;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun 
passwd_abort(uint64_t etime)51*4882a593Smuzhiyun static int passwd_abort(uint64_t etime)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	const char *sha_env_str = env_get("bootstopkeysha256");
54*4882a593Smuzhiyun 	u8 sha_env[SHA256_SUM_LEN];
55*4882a593Smuzhiyun 	u8 sha[SHA256_SUM_LEN];
56*4882a593Smuzhiyun 	char presskey[MAX_DELAY_STOP_STR];
57*4882a593Smuzhiyun 	const char *algo_name = "sha256";
58*4882a593Smuzhiyun 	u_int presskey_len = 0;
59*4882a593Smuzhiyun 	int abort = 0;
60*4882a593Smuzhiyun 	int size;
61*4882a593Smuzhiyun 	int ret;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	if (sha_env_str == NULL)
64*4882a593Smuzhiyun 		sha_env_str = CONFIG_AUTOBOOT_STOP_STR_SHA256;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	/*
67*4882a593Smuzhiyun 	 * Generate the binary value from the environment hash value
68*4882a593Smuzhiyun 	 * so that we can compare this value with the computed hash
69*4882a593Smuzhiyun 	 * from the user input
70*4882a593Smuzhiyun 	 */
71*4882a593Smuzhiyun 	ret = hash_parse_string(algo_name, sha_env_str, sha_env);
72*4882a593Smuzhiyun 	if (ret) {
73*4882a593Smuzhiyun 		printf("Hash %s not supported!\n", algo_name);
74*4882a593Smuzhiyun 		return 0;
75*4882a593Smuzhiyun 	}
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	/*
78*4882a593Smuzhiyun 	 * We don't know how long the stop-string is, so we need to
79*4882a593Smuzhiyun 	 * generate the sha256 hash upon each input character and
80*4882a593Smuzhiyun 	 * compare the value with the one saved in the environment
81*4882a593Smuzhiyun 	 */
82*4882a593Smuzhiyun 	do {
83*4882a593Smuzhiyun 		if (tstc()) {
84*4882a593Smuzhiyun 			/* Check for input string overflow */
85*4882a593Smuzhiyun 			if (presskey_len >= MAX_DELAY_STOP_STR)
86*4882a593Smuzhiyun 				return 0;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 			presskey[presskey_len++] = getc();
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 			/* Calculate sha256 upon each new char */
91*4882a593Smuzhiyun 			hash_block(algo_name, (const void *)presskey,
92*4882a593Smuzhiyun 				   presskey_len, sha, &size);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 			/* And check if sha matches saved value in env */
95*4882a593Smuzhiyun 			if (slow_equals(sha, sha_env, SHA256_SUM_LEN))
96*4882a593Smuzhiyun 				abort = 1;
97*4882a593Smuzhiyun 		}
98*4882a593Smuzhiyun 	} while (!abort && get_ticks() <= etime);
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	return abort;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun #else
passwd_abort(uint64_t etime)103*4882a593Smuzhiyun static int passwd_abort(uint64_t etime)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	int abort = 0;
106*4882a593Smuzhiyun 	struct {
107*4882a593Smuzhiyun 		char *str;
108*4882a593Smuzhiyun 		u_int len;
109*4882a593Smuzhiyun 		int retry;
110*4882a593Smuzhiyun 	}
111*4882a593Smuzhiyun 	delaykey[] = {
112*4882a593Smuzhiyun 		{ .str = env_get("bootdelaykey"),  .retry = 1 },
113*4882a593Smuzhiyun 		{ .str = env_get("bootstopkey"),   .retry = 0 },
114*4882a593Smuzhiyun 	};
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	char presskey[MAX_DELAY_STOP_STR];
117*4882a593Smuzhiyun 	u_int presskey_len = 0;
118*4882a593Smuzhiyun 	u_int presskey_max = 0;
119*4882a593Smuzhiyun 	u_int i;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun #  ifdef CONFIG_AUTOBOOT_DELAY_STR
122*4882a593Smuzhiyun 	if (delaykey[0].str == NULL)
123*4882a593Smuzhiyun 		delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
124*4882a593Smuzhiyun #  endif
125*4882a593Smuzhiyun #  ifdef CONFIG_AUTOBOOT_STOP_STR
126*4882a593Smuzhiyun 	if (delaykey[1].str == NULL)
127*4882a593Smuzhiyun 		delaykey[1].str = CONFIG_AUTOBOOT_STOP_STR;
128*4882a593Smuzhiyun #  endif
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
131*4882a593Smuzhiyun 		delaykey[i].len = delaykey[i].str == NULL ?
132*4882a593Smuzhiyun 				    0 : strlen(delaykey[i].str);
133*4882a593Smuzhiyun 		delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
134*4882a593Smuzhiyun 				    MAX_DELAY_STOP_STR : delaykey[i].len;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 		presskey_max = presskey_max > delaykey[i].len ?
137*4882a593Smuzhiyun 				    presskey_max : delaykey[i].len;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 		debug_bootkeys("%s key:<%s>\n",
140*4882a593Smuzhiyun 			       delaykey[i].retry ? "delay" : "stop",
141*4882a593Smuzhiyun 			       delaykey[i].str ? delaykey[i].str : "NULL");
142*4882a593Smuzhiyun 	}
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	/* In order to keep up with incoming data, check timeout only
145*4882a593Smuzhiyun 	 * when catch up.
146*4882a593Smuzhiyun 	 */
147*4882a593Smuzhiyun 	do {
148*4882a593Smuzhiyun 		if (tstc()) {
149*4882a593Smuzhiyun 			if (presskey_len < presskey_max) {
150*4882a593Smuzhiyun 				presskey[presskey_len++] = getc();
151*4882a593Smuzhiyun 			} else {
152*4882a593Smuzhiyun 				for (i = 0; i < presskey_max - 1; i++)
153*4882a593Smuzhiyun 					presskey[i] = presskey[i + 1];
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 				presskey[i] = getc();
156*4882a593Smuzhiyun 			}
157*4882a593Smuzhiyun 		}
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 		for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
160*4882a593Smuzhiyun 			if (delaykey[i].len > 0 &&
161*4882a593Smuzhiyun 			    presskey_len >= delaykey[i].len &&
162*4882a593Smuzhiyun 				memcmp(presskey + presskey_len -
163*4882a593Smuzhiyun 					delaykey[i].len, delaykey[i].str,
164*4882a593Smuzhiyun 					delaykey[i].len) == 0) {
165*4882a593Smuzhiyun 					debug_bootkeys("got %skey\n",
166*4882a593Smuzhiyun 						delaykey[i].retry ? "delay" :
167*4882a593Smuzhiyun 						"stop");
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 				/* don't retry auto boot */
170*4882a593Smuzhiyun 				if (!delaykey[i].retry)
171*4882a593Smuzhiyun 					bootretry_dont_retry();
172*4882a593Smuzhiyun 				abort = 1;
173*4882a593Smuzhiyun 			}
174*4882a593Smuzhiyun 		}
175*4882a593Smuzhiyun 	} while (!abort && get_ticks() <= etime);
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	return abort;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun #endif
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun /***************************************************************************
182*4882a593Smuzhiyun  * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
183*4882a593Smuzhiyun  * returns: 0 -  no key string, allow autoboot 1 - got key string, abort
184*4882a593Smuzhiyun  */
__abortboot(int bootdelay)185*4882a593Smuzhiyun static int __abortboot(int bootdelay)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun 	int abort;
188*4882a593Smuzhiyun 	uint64_t etime = endtick(bootdelay);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun #  ifdef CONFIG_AUTOBOOT_PROMPT
191*4882a593Smuzhiyun 	/*
192*4882a593Smuzhiyun 	 * CONFIG_AUTOBOOT_PROMPT includes the %d for all boards.
193*4882a593Smuzhiyun 	 * To print the bootdelay value upon bootup.
194*4882a593Smuzhiyun 	 */
195*4882a593Smuzhiyun 	printf(CONFIG_AUTOBOOT_PROMPT, bootdelay);
196*4882a593Smuzhiyun #  endif
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	abort = passwd_abort(etime);
199*4882a593Smuzhiyun 	if (!abort)
200*4882a593Smuzhiyun 		debug_bootkeys("key timeout\n");
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	return abort;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun # else	/* !defined(CONFIG_AUTOBOOT_KEYED) */
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun #ifdef CONFIG_MENUKEY
208*4882a593Smuzhiyun static int menukey;
209*4882a593Smuzhiyun #endif
210*4882a593Smuzhiyun 
__abortboot(int bootdelay)211*4882a593Smuzhiyun static int __abortboot(int bootdelay)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	int abort = 0;
214*4882a593Smuzhiyun 	unsigned long ts;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun #ifdef CONFIG_MENUPROMPT
217*4882a593Smuzhiyun 	printf(CONFIG_MENUPROMPT);
218*4882a593Smuzhiyun #else
219*4882a593Smuzhiyun 	printf("Hit key to stop autoboot('CTRL+C'): %2d ", bootdelay);
220*4882a593Smuzhiyun #endif
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun #ifdef CONFIG_ARCH_ROCKCHIP
223*4882a593Smuzhiyun 	if (!IS_ENABLED(CONFIG_CONSOLE_DISABLE_CLI) && ctrlc()) {	/* we press ctrl+c ? */
224*4882a593Smuzhiyun #else
225*4882a593Smuzhiyun 	/*
226*4882a593Smuzhiyun 	 * Check if key already pressed
227*4882a593Smuzhiyun 	 */
228*4882a593Smuzhiyun 	if (tstc()) {	/* we got a key press	*/
229*4882a593Smuzhiyun #endif
230*4882a593Smuzhiyun 		(void) getc();  /* consume input	*/
231*4882a593Smuzhiyun 		puts("\b\b\b 0");
232*4882a593Smuzhiyun 		abort = 1;	/* don't auto boot	*/
233*4882a593Smuzhiyun 	}
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	while ((bootdelay > 0) && (!abort)) {
236*4882a593Smuzhiyun 		--bootdelay;
237*4882a593Smuzhiyun 		/* delay 1000 ms */
238*4882a593Smuzhiyun 		ts = get_timer(0);
239*4882a593Smuzhiyun 		do {
240*4882a593Smuzhiyun 			if (ctrlc()) {	/* we got a ctrl+c key press	*/
241*4882a593Smuzhiyun 				abort  = 1;	/* don't auto boot	*/
242*4882a593Smuzhiyun 				bootdelay = 0;	/* no more delay	*/
243*4882a593Smuzhiyun # ifdef CONFIG_MENUKEY
244*4882a593Smuzhiyun 				menukey = 0x03;	/* ctrl+c key code */
245*4882a593Smuzhiyun # endif
246*4882a593Smuzhiyun 				break;
247*4882a593Smuzhiyun 			}
248*4882a593Smuzhiyun 			udelay(10000);
249*4882a593Smuzhiyun 		} while (!abort && get_timer(ts) < 1000);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 		printf("\b\b\b%2d ", bootdelay);
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	putc('\n');
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	return abort;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun # endif	/* CONFIG_AUTOBOOT_KEYED */
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun static int abortboot(int bootdelay)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	int abort = 0;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	if (bootdelay >= 0)
265*4882a593Smuzhiyun 		abort = __abortboot(bootdelay);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun #ifdef CONFIG_SILENT_CONSOLE
268*4882a593Smuzhiyun 	if (abort)
269*4882a593Smuzhiyun 		gd->flags &= ~GD_FLG_SILENT;
270*4882a593Smuzhiyun #endif
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	return abort;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun static void process_fdt_options(const void *blob)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun #if defined(CONFIG_OF_CONTROL) && defined(CONFIG_SYS_TEXT_BASE)
278*4882a593Smuzhiyun 	ulong addr;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	/* Add an env variable to point to a kernel payload, if available */
281*4882a593Smuzhiyun 	addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0);
282*4882a593Smuzhiyun 	if (addr)
283*4882a593Smuzhiyun 		env_set_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	/* Add an env variable to point to a root disk, if available */
286*4882a593Smuzhiyun 	addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0);
287*4882a593Smuzhiyun 	if (addr)
288*4882a593Smuzhiyun 		env_set_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
289*4882a593Smuzhiyun #endif /* CONFIG_OF_CONTROL && CONFIG_SYS_TEXT_BASE */
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun const char *bootdelay_process(void)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	char *s;
295*4882a593Smuzhiyun 	int bootdelay;
296*4882a593Smuzhiyun #ifdef CONFIG_BOOTCOUNT_LIMIT
297*4882a593Smuzhiyun 	unsigned long bootcount = 0;
298*4882a593Smuzhiyun 	unsigned long bootlimit = 0;
299*4882a593Smuzhiyun #endif /* CONFIG_BOOTCOUNT_LIMIT */
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun #ifdef CONFIG_BOOTCOUNT_LIMIT
302*4882a593Smuzhiyun 	bootcount = bootcount_load();
303*4882a593Smuzhiyun 	bootcount++;
304*4882a593Smuzhiyun 	bootcount_store(bootcount);
305*4882a593Smuzhiyun 	env_set_ulong("bootcount", bootcount);
306*4882a593Smuzhiyun 	bootlimit = env_get_ulong("bootlimit", 10, 0);
307*4882a593Smuzhiyun #endif /* CONFIG_BOOTCOUNT_LIMIT */
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	s = env_get("bootdelay");
310*4882a593Smuzhiyun 	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun #ifdef CONFIG_OF_CONTROL
313*4882a593Smuzhiyun 	bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
314*4882a593Smuzhiyun 			bootdelay);
315*4882a593Smuzhiyun #endif
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun #if defined(CONFIG_MENU_SHOW)
320*4882a593Smuzhiyun 	bootdelay = menu_show(bootdelay);
321*4882a593Smuzhiyun #endif
322*4882a593Smuzhiyun 	bootretry_init_cmd_timeout();
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun #ifdef CONFIG_POST
325*4882a593Smuzhiyun 	if (gd->flags & GD_FLG_POSTFAIL) {
326*4882a593Smuzhiyun 		s = env_get("failbootcmd");
327*4882a593Smuzhiyun 	} else
328*4882a593Smuzhiyun #endif /* CONFIG_POST */
329*4882a593Smuzhiyun #ifdef CONFIG_BOOTCOUNT_LIMIT
330*4882a593Smuzhiyun 	if (bootlimit && (bootcount > bootlimit)) {
331*4882a593Smuzhiyun 		printf("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
332*4882a593Smuzhiyun 		       (unsigned)bootlimit);
333*4882a593Smuzhiyun 		s = env_get("altbootcmd");
334*4882a593Smuzhiyun 	} else
335*4882a593Smuzhiyun #endif /* CONFIG_BOOTCOUNT_LIMIT */
336*4882a593Smuzhiyun 		s = env_get("bootcmd");
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	process_fdt_options(gd->fdt_blob);
339*4882a593Smuzhiyun 	stored_bootdelay = bootdelay;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	return s;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun /*
345*4882a593Smuzhiyun  * Board-specific Platform code can reimplement autoboot_command_fail_handle ()
346*4882a593Smuzhiyun  * if needed
347*4882a593Smuzhiyun  */
348*4882a593Smuzhiyun __weak void autoboot_command_fail_handle(void) {}
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun void autoboot_command(const char *s)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun 	debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
355*4882a593Smuzhiyun #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
356*4882a593Smuzhiyun 		int prev = disable_ctrlc(1);	/* disable Control C checking */
357*4882a593Smuzhiyun #endif
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 		run_command_list(s, -1, 0);
360*4882a593Smuzhiyun 		autoboot_command_fail_handle();
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
363*4882a593Smuzhiyun 		disable_ctrlc(prev);	/* restore Control C checking */
364*4882a593Smuzhiyun #endif
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun #ifdef CONFIG_MENUKEY
368*4882a593Smuzhiyun 	if (menukey == CONFIG_MENUKEY) {
369*4882a593Smuzhiyun 		s = env_get("menucmd");
370*4882a593Smuzhiyun 		if (s)
371*4882a593Smuzhiyun 			run_command_list(s, -1, 0);
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun #endif /* CONFIG_MENUKEY */
374*4882a593Smuzhiyun }
375