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