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