Blame view

common/autoboot.c 8.81 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
66ded17df   Simon Glass   Move autoboot cod...
2
3
4
  /*
   * (C) Copyright 2000
   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
66ded17df   Simon Glass   Move autoboot cod...
5
6
7
   */
  
  #include <common.h>
39e1230ed   Jeroen Hofstee   autoboot: add its...
8
  #include <autoboot.h>
0098e179e   Simon Glass   Move bootretry co...
9
  #include <bootretry.h>
66ded17df   Simon Glass   Move autoboot cod...
10
  #include <cli.h>
24b852a7a   Simon Glass   Move console defi...
11
  #include <console.h>
c7694dd48   Simon Glass   env: Move env_set...
12
  #include <env.h>
66ded17df   Simon Glass   Move autoboot cod...
13
  #include <fdtdec.h>
e8c780560   Simon Glass   autoboot: Drop #i...
14
  #include <hash.h>
ecaae801d   Heiko Schocher   autoboot: fix bug...
15
  #include <memalign.h>
66ded17df   Simon Glass   Move autoboot cod...
16
17
  #include <menu.h>
  #include <post.h>
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
18
  #include <u-boot/sha256.h>
bc8c440fa   Lukasz Majewski   bootcount: Rewrit...
19
  #include <bootcount.h>
66ded17df   Simon Glass   Move autoboot cod...
20
21
22
23
24
25
26
27
28
29
  
  DECLARE_GLOBAL_DATA_PTR;
  
  #define MAX_DELAY_STOP_STR 32
  
  #ifndef DEBUG_BOOTKEYS
  #define DEBUG_BOOTKEYS 0
  #endif
  #define debug_bootkeys(fmt, args...)		\
  	debug_cond(DEBUG_BOOTKEYS, fmt, ##args)
affb21562   Simon Glass   main: Make the ex...
30
31
  /* Stored value of bootdelay, used by autoboot_command() */
  static int stored_bootdelay;
d915ad277   Simon Glass   autoboot: Tidy up...
32
  static int menukey;
affb21562   Simon Glass   main: Make the ex...
33

0c4bd318f   Simon Glass   autoboot: Use CON...
34
35
36
37
38
  #ifdef CONFIG_AUTOBOOT_ENCRYPTION
  #define AUTOBOOT_STOP_STR_SHA256 CONFIG_AUTOBOOT_STOP_STR_SHA256
  #else
  #define AUTOBOOT_STOP_STR_SHA256 ""
  #endif
d915ad277   Simon Glass   autoboot: Tidy up...
39
40
41
42
43
  #ifdef CONFIG_USE_AUTOBOOT_MENUKEY
  #define AUTOBOOT_MENUKEY CONFIG_USE_AUTOBOOT_MENUKEY
  #else
  #define AUTOBOOT_MENUKEY 0
  #endif
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
44
45
46
47
48
  /*
   * Use a "constant-length" time compare function for this
   * hash compare:
   *
   * https://crackstation.net/hashing-security.htm
66ded17df   Simon Glass   Move autoboot cod...
49
   */
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
50
51
52
53
54
55
56
57
58
59
  static int slow_equals(u8 *a, u8 *b, int len)
  {
  	int diff = 0;
  	int i;
  
  	for (i = 0; i < len; i++)
  		diff |= a[i] ^ b[i];
  
  	return diff == 0;
  }
88fa4beb6   Simon Glass   autoboot: Improve...
60
61
62
63
64
65
66
67
  /**
   * passwd_abort_sha256() - check for a hashed key sequence to abort booting
   *
   * This checks for the user entering a SHA256 hash within a given time.
   *
   * @etime: Timeout value ticks (stop when get_ticks() reachs this)
   * @return 0 if autoboot should continue, 1 if it should stop
   */
e8c780560   Simon Glass   autoboot: Drop #i...
68
  static int passwd_abort_sha256(uint64_t etime)
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
69
  {
00caae6d4   Simon Glass   env: Rename geten...
70
  	const char *sha_env_str = env_get("bootstopkeysha256");
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
71
  	u8 sha_env[SHA256_SUM_LEN];
ecaae801d   Heiko Schocher   autoboot: fix bug...
72
73
  	u8 *sha;
  	char *presskey;
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
74
75
76
  	const char *algo_name = "sha256";
  	u_int presskey_len = 0;
  	int abort = 0;
2d06fd839   Martin Etnestad   Initialize SHA bu...
77
  	int size = sizeof(sha);
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
78
79
80
  	int ret;
  
  	if (sha_env_str == NULL)
0c4bd318f   Simon Glass   autoboot: Use CON...
81
  		sha_env_str = AUTOBOOT_STOP_STR_SHA256;
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
82
83
84
85
86
87
88
89
90
91
92
93
  
  	/*
  	 * Generate the binary value from the environment hash value
  	 * so that we can compare this value with the computed hash
  	 * from the user input
  	 */
  	ret = hash_parse_string(algo_name, sha_env_str, sha_env);
  	if (ret) {
  		printf("Hash %s not supported!
  ", algo_name);
  		return 0;
  	}
ecaae801d   Heiko Schocher   autoboot: fix bug...
94
95
96
  	presskey = malloc_cache_aligned(MAX_DELAY_STOP_STR);
  	sha = malloc_cache_aligned(SHA256_SUM_LEN);
  	size = SHA256_SUM_LEN;
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
97
98
99
100
101
102
103
104
  	/*
  	 * We don't know how long the stop-string is, so we need to
  	 * generate the sha256 hash upon each input character and
  	 * compare the value with the one saved in the environment
  	 */
  	do {
  		if (tstc()) {
  			/* Check for input string overflow */
ecaae801d   Heiko Schocher   autoboot: fix bug...
105
106
107
  			if (presskey_len >= MAX_DELAY_STOP_STR) {
  				free(presskey);
  				free(sha);
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
108
  				return 0;
ecaae801d   Heiko Schocher   autoboot: fix bug...
109
  			}
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
110
111
112
113
114
115
116
117
118
119
120
121
  
  			presskey[presskey_len++] = getc();
  
  			/* Calculate sha256 upon each new char */
  			hash_block(algo_name, (const void *)presskey,
  				   presskey_len, sha, &size);
  
  			/* And check if sha matches saved value in env */
  			if (slow_equals(sha, sha_env, SHA256_SUM_LEN))
  				abort = 1;
  		}
  	} while (!abort && get_ticks() <= etime);
ecaae801d   Heiko Schocher   autoboot: fix bug...
122
123
  	free(presskey);
  	free(sha);
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
124
125
  	return abort;
  }
e8c780560   Simon Glass   autoboot: Drop #i...
126

88fa4beb6   Simon Glass   autoboot: Improve...
127
128
129
130
131
132
133
134
  /**
   * passwd_abort_key() - check for a key sequence to aborted booting
   *
   * This checks for the user entering a string within a given time.
   *
   * @etime: Timeout value ticks (stop when get_ticks() reachs this)
   * @return 0 if autoboot should continue, 1 if it should stop
   */
e8c780560   Simon Glass   autoboot: Drop #i...
135
  static int passwd_abort_key(uint64_t etime)
66ded17df   Simon Glass   Move autoboot cod...
136
137
  {
  	int abort = 0;
66ded17df   Simon Glass   Move autoboot cod...
138
139
140
141
142
143
  	struct {
  		char *str;
  		u_int len;
  		int retry;
  	}
  	delaykey[] = {
00caae6d4   Simon Glass   env: Rename geten...
144
145
  		{ .str = env_get("bootdelaykey"),  .retry = 1 },
  		{ .str = env_get("bootstopkey"),   .retry = 0 },
66ded17df   Simon Glass   Move autoboot cod...
146
147
148
149
150
151
  	};
  
  	char presskey[MAX_DELAY_STOP_STR];
  	u_int presskey_len = 0;
  	u_int presskey_max = 0;
  	u_int i;
66ded17df   Simon Glass   Move autoboot cod...
152
153
154
155
  #  ifdef CONFIG_AUTOBOOT_DELAY_STR
  	if (delaykey[0].str == NULL)
  		delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
  #  endif
66ded17df   Simon Glass   Move autoboot cod...
156
  #  ifdef CONFIG_AUTOBOOT_STOP_STR
2d908fa08   Stefan Roese   autoboot.c: Remov...
157
158
  	if (delaykey[1].str == NULL)
  		delaykey[1].str = CONFIG_AUTOBOOT_STOP_STR;
66ded17df   Simon Glass   Move autoboot cod...
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  #  endif
  
  	for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
  		delaykey[i].len = delaykey[i].str == NULL ?
  				    0 : strlen(delaykey[i].str);
  		delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
  				    MAX_DELAY_STOP_STR : delaykey[i].len;
  
  		presskey_max = presskey_max > delaykey[i].len ?
  				    presskey_max : delaykey[i].len;
  
  		debug_bootkeys("%s key:<%s>
  ",
  			       delaykey[i].retry ? "delay" : "stop",
  			       delaykey[i].str ? delaykey[i].str : "NULL");
  	}
  
  	/* In order to keep up with incoming data, check timeout only
  	 * when catch up.
  	 */
  	do {
  		if (tstc()) {
  			if (presskey_len < presskey_max) {
  				presskey[presskey_len++] = getc();
  			} else {
  				for (i = 0; i < presskey_max - 1; i++)
  					presskey[i] = presskey[i + 1];
  
  				presskey[i] = getc();
  			}
  		}
  
  		for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
  			if (delaykey[i].len > 0 &&
  			    presskey_len >= delaykey[i].len &&
  				memcmp(presskey + presskey_len -
  					delaykey[i].len, delaykey[i].str,
  					delaykey[i].len) == 0) {
  					debug_bootkeys("got %skey
  ",
  						delaykey[i].retry ? "delay" :
  						"stop");
66ded17df   Simon Glass   Move autoboot cod...
201
202
203
  				/* don't retry auto boot */
  				if (!delaykey[i].retry)
  					bootretry_dont_retry();
66ded17df   Simon Glass   Move autoboot cod...
204
205
206
207
  				abort = 1;
  			}
  		}
  	} while (!abort && get_ticks() <= etime);
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
208
209
  	return abort;
  }
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
210
211
212
213
214
  
  /***************************************************************************
   * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
   * returns: 0 -  no key string, allow autoboot 1 - got key string, abort
   */
e79e4b250   Simon Glass   autoboot: Drop #i...
215
  static int abortboot_key_sequence(int bootdelay)
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
216
217
218
  {
  	int abort;
  	uint64_t etime = endtick(bootdelay);
8f0b1e24e   Stefan Roese   autoboot.c: Add f...
219
220
221
222
223
224
225
  #  ifdef CONFIG_AUTOBOOT_PROMPT
  	/*
  	 * CONFIG_AUTOBOOT_PROMPT includes the %d for all boards.
  	 * To print the bootdelay value upon bootup.
  	 */
  	printf(CONFIG_AUTOBOOT_PROMPT, bootdelay);
  #  endif
e8c780560   Simon Glass   autoboot: Drop #i...
226
227
228
229
  	if (IS_ENABLED(CONFIG_AUTOBOOT_ENCRYPTION))
  		abort = passwd_abort_sha256(etime);
  	else
  		abort = passwd_abort_key(etime);
66ded17df   Simon Glass   Move autoboot cod...
230
231
232
  	if (!abort)
  		debug_bootkeys("key timeout
  ");
66ded17df   Simon Glass   Move autoboot cod...
233
234
  	return abort;
  }
e79e4b250   Simon Glass   autoboot: Drop #i...
235
  static int abortboot_single_key(int bootdelay)
66ded17df   Simon Glass   Move autoboot cod...
236
237
238
  {
  	int abort = 0;
  	unsigned long ts;
463273920   Masahiro Yamada   autoboot: move bo...
239
  	printf("Hit any key to stop autoboot: %2d ", bootdelay);
66ded17df   Simon Glass   Move autoboot cod...
240

66ded17df   Simon Glass   Move autoboot cod...
241
242
  	/*
  	 * Check if key already pressed
66ded17df   Simon Glass   Move autoboot cod...
243
  	 */
463273920   Masahiro Yamada   autoboot: move bo...
244
245
246
247
  	if (tstc()) {	/* we got a key press	*/
  		(void) getc();  /* consume input	*/
  		puts("\b\b\b 0");
  		abort = 1;	/* don't auto boot	*/
66ded17df   Simon Glass   Move autoboot cod...
248
  	}
66ded17df   Simon Glass   Move autoboot cod...
249
250
251
252
253
254
255
  
  	while ((bootdelay > 0) && (!abort)) {
  		--bootdelay;
  		/* delay 1000 ms */
  		ts = get_timer(0);
  		do {
  			if (tstc()) {	/* we got a key press	*/
d915ad277   Simon Glass   autoboot: Tidy up...
256
  				int key;
66ded17df   Simon Glass   Move autoboot cod...
257
258
  				abort  = 1;	/* don't auto boot	*/
  				bootdelay = 0;	/* no more delay	*/
d915ad277   Simon Glass   autoboot: Tidy up...
259
260
261
  				key = getc(); /* consume input	*/
  				if (IS_ENABLED(CONFIG_USE_AUTOBOOT_MENUKEY))
  					menukey = key;
66ded17df   Simon Glass   Move autoboot cod...
262
263
264
265
266
267
268
269
270
271
  				break;
  			}
  			udelay(10000);
  		} while (!abort && get_timer(ts) < 1000);
  
  		printf("\b\b\b%2d ", bootdelay);
  	}
  
  	putc('
  ');
66ded17df   Simon Glass   Move autoboot cod...
272
273
  	return abort;
  }
66ded17df   Simon Glass   Move autoboot cod...
274
275
276
  
  static int abortboot(int bootdelay)
  {
463273920   Masahiro Yamada   autoboot: move bo...
277
  	int abort = 0;
09b9d9e55   Masahiro Yamada   autoboot: move CO...
278

e79e4b250   Simon Glass   autoboot: Drop #i...
279
280
281
282
283
284
  	if (bootdelay >= 0) {
  		if (IS_ENABLED(CONFIG_AUTOBOOT_KEYED))
  			abort = abortboot_key_sequence(bootdelay);
  		else
  			abort = abortboot_single_key(bootdelay);
  	}
09b9d9e55   Masahiro Yamada   autoboot: move CO...
285

42b4d14e3   Simon Glass   autoboot: Use if(...
286
  	if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && abort)
09b9d9e55   Masahiro Yamada   autoboot: move CO...
287
  		gd->flags &= ~GD_FLG_SILENT;
09b9d9e55   Masahiro Yamada   autoboot: move CO...
288
289
  
  	return abort;
66ded17df   Simon Glass   Move autoboot cod...
290
  }
66ded17df   Simon Glass   Move autoboot cod...
291
292
  static void process_fdt_options(const void *blob)
  {
5fa3fd25e   Simon Glass   autoboot: Move a ...
293
  #ifdef CONFIG_SYS_TEXT_BASE
66ded17df   Simon Glass   Move autoboot cod...
294
295
296
297
298
  	ulong addr;
  
  	/* Add an env variable to point to a kernel payload, if available */
  	addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0);
  	if (addr)
018f53032   Simon Glass   env: Rename commo...
299
  		env_set_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
66ded17df   Simon Glass   Move autoboot cod...
300
301
302
303
  
  	/* Add an env variable to point to a root disk, if available */
  	addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0);
  	if (addr)
018f53032   Simon Glass   env: Rename commo...
304
  		env_set_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
5fa3fd25e   Simon Glass   autoboot: Move a ...
305
  #endif /* CONFIG_SYS_TEXT_BASE */
affb21562   Simon Glass   main: Make the ex...
306
  }
66ded17df   Simon Glass   Move autoboot cod...
307

affb21562   Simon Glass   main: Make the ex...
308
  const char *bootdelay_process(void)
66ded17df   Simon Glass   Move autoboot cod...
309
  {
66ded17df   Simon Glass   Move autoboot cod...
310
311
  	char *s;
  	int bootdelay;
bc8c440fa   Lukasz Majewski   bootcount: Rewrit...
312
313
  
  	bootcount_inc();
66ded17df   Simon Glass   Move autoboot cod...
314

00caae6d4   Simon Glass   env: Rename geten...
315
  	s = env_get("bootdelay");
66ded17df   Simon Glass   Move autoboot cod...
316
  	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
5fa3fd25e   Simon Glass   autoboot: Move a ...
317
318
319
  	if (IS_ENABLED(CONFIG_OF_CONTROL))
  		bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
  						  bootdelay);
66ded17df   Simon Glass   Move autoboot cod...
320
321
322
323
  
  	debug("### main_loop entered: bootdelay=%d
  
  ", bootdelay);
5fa3fd25e   Simon Glass   autoboot: Move a ...
324
325
  	if (IS_ENABLED(CONFIG_AUTOBOOT_MENU_SHOW))
  		bootdelay = menu_show(bootdelay);
b26440f1f   Simon Glass   Rename bootretry ...
326
  	bootretry_init_cmd_timeout();
66ded17df   Simon Glass   Move autoboot cod...
327
328
329
  
  #ifdef CONFIG_POST
  	if (gd->flags & GD_FLG_POSTFAIL) {
00caae6d4   Simon Glass   env: Rename geten...
330
  		s = env_get("failbootcmd");
66ded17df   Simon Glass   Move autoboot cod...
331
332
  	} else
  #endif /* CONFIG_POST */
bc8c440fa   Lukasz Majewski   bootcount: Rewrit...
333
  	if (bootcount_error())
00caae6d4   Simon Glass   env: Rename geten...
334
  		s = env_get("altbootcmd");
bc8c440fa   Lukasz Majewski   bootcount: Rewrit...
335
  	else
00caae6d4   Simon Glass   env: Rename geten...
336
  		s = env_get("bootcmd");
66ded17df   Simon Glass   Move autoboot cod...
337

5fa3fd25e   Simon Glass   autoboot: Move a ...
338
339
  	if (IS_ENABLED(CONFIG_OF_CONTROL))
  		process_fdt_options(gd->fdt_blob);
affb21562   Simon Glass   main: Make the ex...
340
  	stored_bootdelay = bootdelay;
66ded17df   Simon Glass   Move autoboot cod...
341

affb21562   Simon Glass   main: Make the ex...
342
343
  	return s;
  }
66ded17df   Simon Glass   Move autoboot cod...
344

affb21562   Simon Glass   main: Make the ex...
345
346
  void autoboot_command(const char *s)
  {
66ded17df   Simon Glass   Move autoboot cod...
347
348
  	debug("### main_loop: bootcmd=\"%s\"
  ", s ? s : "<UNDEFINED>");
affb21562   Simon Glass   main: Make the ex...
349
  	if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
5ec35ff3e   Simon Glass   autoboot: Adjust ...
350
351
352
353
354
355
356
  		bool lock;
  		int prev;
  
  		lock = IS_ENABLED(CONFIG_AUTOBOOT_KEYED) &&
  			!IS_ENABLED(CONFIG_AUTOBOOT_KEYED_CTRLC);
  		if (lock)
  			prev = disable_ctrlc(1); /* disable Ctrl-C checking */
66ded17df   Simon Glass   Move autoboot cod...
357
358
  
  		run_command_list(s, -1, 0);
5ec35ff3e   Simon Glass   autoboot: Adjust ...
359
360
  		if (lock)
  			disable_ctrlc(prev);	/* restore Ctrl-C checking */
66ded17df   Simon Glass   Move autoboot cod...
361
  	}
d915ad277   Simon Glass   autoboot: Tidy up...
362
363
  	if (IS_ENABLED(CONFIG_USE_AUTOBOOT_MENUKEY) &&
  	    menukey == AUTOBOOT_MENUKEY) {
00caae6d4   Simon Glass   env: Rename geten...
364
  		s = env_get("menucmd");
66ded17df   Simon Glass   Move autoboot cod...
365
366
367
  		if (s)
  			run_command_list(s, -1, 0);
  	}
66ded17df   Simon Glass   Move autoboot cod...
368
  }