xref: /openbmc/u-boot/common/autoboot.c (revision 21299d3a)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6 
7 #include <common.h>
8 #include <autoboot.h>
9 #include <bootretry.h>
10 #include <cli.h>
11 #include <console.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 = env_get("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 = sizeof(sha);
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 = env_get("bootdelaykey"),  .retry = 1 },
112 		{ .str = env_get("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(int bootdelay)
185 {
186 	int abort;
187 	uint64_t etime = endtick(bootdelay);
188 
189 #  ifdef CONFIG_AUTOBOOT_PROMPT
190 	/*
191 	 * CONFIG_AUTOBOOT_PROMPT includes the %d for all boards.
192 	 * To print the bootdelay value upon bootup.
193 	 */
194 	printf(CONFIG_AUTOBOOT_PROMPT, bootdelay);
195 #  endif
196 
197 	abort = passwd_abort(etime);
198 	if (!abort)
199 		debug_bootkeys("key timeout\n");
200 
201 	return abort;
202 }
203 
204 # else	/* !defined(CONFIG_AUTOBOOT_KEYED) */
205 
206 #ifdef CONFIG_MENUKEY
207 static int menukey;
208 #endif
209 
210 static int __abortboot(int bootdelay)
211 {
212 	int abort = 0;
213 	unsigned long ts;
214 
215 #ifdef CONFIG_MENUPROMPT
216 	printf(CONFIG_MENUPROMPT);
217 #else
218 	printf("Hit any key to stop autoboot: %2d ", bootdelay);
219 #endif
220 
221 	/*
222 	 * Check if key already pressed
223 	 */
224 	if (tstc()) {	/* we got a key press	*/
225 		(void) getc();  /* consume input	*/
226 		puts("\b\b\b 0");
227 		abort = 1;	/* don't auto boot	*/
228 	}
229 
230 	while ((bootdelay > 0) && (!abort)) {
231 		--bootdelay;
232 		/* delay 1000 ms */
233 		ts = get_timer(0);
234 		do {
235 			if (tstc()) {	/* we got a key press	*/
236 				abort  = 1;	/* don't auto boot	*/
237 				bootdelay = 0;	/* no more delay	*/
238 # ifdef CONFIG_MENUKEY
239 				menukey = getc();
240 # else
241 				(void) getc();  /* consume input	*/
242 # endif
243 				break;
244 			}
245 			udelay(10000);
246 		} while (!abort && get_timer(ts) < 1000);
247 
248 		printf("\b\b\b%2d ", bootdelay);
249 	}
250 
251 	putc('\n');
252 
253 	return abort;
254 }
255 # endif	/* CONFIG_AUTOBOOT_KEYED */
256 
257 static int abortboot(int bootdelay)
258 {
259 	int abort = 0;
260 
261 	if (bootdelay >= 0)
262 		abort = __abortboot(bootdelay);
263 
264 #ifdef CONFIG_SILENT_CONSOLE
265 	if (abort)
266 		gd->flags &= ~GD_FLG_SILENT;
267 #endif
268 
269 	return abort;
270 }
271 
272 static void process_fdt_options(const void *blob)
273 {
274 #if defined(CONFIG_OF_CONTROL) && defined(CONFIG_SYS_TEXT_BASE)
275 	ulong addr;
276 
277 	/* Add an env variable to point to a kernel payload, if available */
278 	addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0);
279 	if (addr)
280 		env_set_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
281 
282 	/* Add an env variable to point to a root disk, if available */
283 	addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0);
284 	if (addr)
285 		env_set_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
286 #endif /* CONFIG_OF_CONTROL && CONFIG_SYS_TEXT_BASE */
287 }
288 
289 const char *bootdelay_process(void)
290 {
291 	char *s;
292 	int bootdelay;
293 #ifdef CONFIG_BOOTCOUNT_LIMIT
294 	unsigned long bootcount = 0;
295 	unsigned long bootlimit = 0;
296 #endif /* CONFIG_BOOTCOUNT_LIMIT */
297 
298 #ifdef CONFIG_BOOTCOUNT_LIMIT
299 	bootcount = bootcount_load();
300 	bootcount++;
301 	bootcount_store(bootcount);
302 	env_set_ulong("bootcount", bootcount);
303 	bootlimit = env_get_ulong("bootlimit", 10, 0);
304 #endif /* CONFIG_BOOTCOUNT_LIMIT */
305 
306 	s = env_get("bootdelay");
307 	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
308 
309 #ifdef CONFIG_OF_CONTROL
310 	bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
311 			bootdelay);
312 #endif
313 
314 	debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
315 
316 #if defined(CONFIG_MENU_SHOW)
317 	bootdelay = menu_show(bootdelay);
318 #endif
319 	bootretry_init_cmd_timeout();
320 
321 #ifdef CONFIG_POST
322 	if (gd->flags & GD_FLG_POSTFAIL) {
323 		s = env_get("failbootcmd");
324 	} else
325 #endif /* CONFIG_POST */
326 #ifdef CONFIG_BOOTCOUNT_LIMIT
327 	if (bootlimit && (bootcount > bootlimit)) {
328 		printf("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
329 		       (unsigned)bootlimit);
330 		s = env_get("altbootcmd");
331 	} else
332 #endif /* CONFIG_BOOTCOUNT_LIMIT */
333 		s = env_get("bootcmd");
334 
335 	process_fdt_options(gd->fdt_blob);
336 	stored_bootdelay = bootdelay;
337 
338 	return s;
339 }
340 
341 void autoboot_command(const char *s)
342 {
343 	debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
344 
345 	if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
346 #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
347 		int prev = disable_ctrlc(1);	/* disable Control C checking */
348 #endif
349 
350 		run_command_list(s, -1, 0);
351 
352 #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
353 		disable_ctrlc(prev);	/* restore Control C checking */
354 #endif
355 	}
356 
357 #ifdef CONFIG_MENUKEY
358 	if (menukey == CONFIG_MENUKEY) {
359 		s = env_get("menucmd");
360 		if (s)
361 			run_command_list(s, -1, 0);
362 	}
363 #endif /* CONFIG_MENUKEY */
364 }
365