mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 07:04:28 +00:00
ecaae801d6
if CONFIG_AUTOBOOT_KEYED, CONFIG_AUTOBOOT_ENCRYPTION and CONFIG_AUTOBOOT_STOP_STR_SHA256 are enabled in conjunction with CONFIG_SHA_HW_ACCEL and CONFIG_FSL_CAAM, we get the Error when pressing a key while waiting for bootdelay: Error: Address arguments are not aligned CAAM was not setup properly or it is faulty Reason is, that used variables are not cache aligned, so malloc this variables cache aligned. Probably this is also a bugfix for other hw accelerators than CAAM. Signed-off-by: Heiko Schocher <hs@denx.de>
381 lines
8.8 KiB
C
381 lines
8.8 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* (C) Copyright 2000
|
|
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <autoboot.h>
|
|
#include <bootretry.h>
|
|
#include <cli.h>
|
|
#include <console.h>
|
|
#include <fdtdec.h>
|
|
#include <hash.h>
|
|
#include <memalign.h>
|
|
#include <menu.h>
|
|
#include <post.h>
|
|
#include <u-boot/sha256.h>
|
|
#include <bootcount.h>
|
|
|
|
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)
|
|
|
|
/* Stored value of bootdelay, used by autoboot_command() */
|
|
static int stored_bootdelay;
|
|
static int menukey;
|
|
|
|
#ifdef CONFIG_AUTOBOOT_ENCRYPTION
|
|
#define AUTOBOOT_STOP_STR_SHA256 CONFIG_AUTOBOOT_STOP_STR_SHA256
|
|
#else
|
|
#define AUTOBOOT_STOP_STR_SHA256 ""
|
|
#endif
|
|
|
|
#ifdef CONFIG_USE_AUTOBOOT_MENUKEY
|
|
#define AUTOBOOT_MENUKEY CONFIG_USE_AUTOBOOT_MENUKEY
|
|
#else
|
|
#define AUTOBOOT_MENUKEY 0
|
|
#endif
|
|
|
|
/*
|
|
* Use a "constant-length" time compare function for this
|
|
* hash compare:
|
|
*
|
|
* https://crackstation.net/hashing-security.htm
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
static int passwd_abort_sha256(uint64_t etime)
|
|
{
|
|
const char *sha_env_str = env_get("bootstopkeysha256");
|
|
u8 sha_env[SHA256_SUM_LEN];
|
|
u8 *sha;
|
|
char *presskey;
|
|
const char *algo_name = "sha256";
|
|
u_int presskey_len = 0;
|
|
int abort = 0;
|
|
int size = sizeof(sha);
|
|
int ret;
|
|
|
|
if (sha_env_str == NULL)
|
|
sha_env_str = AUTOBOOT_STOP_STR_SHA256;
|
|
|
|
/*
|
|
* 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!\n", algo_name);
|
|
return 0;
|
|
}
|
|
|
|
presskey = malloc_cache_aligned(MAX_DELAY_STOP_STR);
|
|
sha = malloc_cache_aligned(SHA256_SUM_LEN);
|
|
size = SHA256_SUM_LEN;
|
|
/*
|
|
* 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 */
|
|
if (presskey_len >= MAX_DELAY_STOP_STR) {
|
|
free(presskey);
|
|
free(sha);
|
|
return 0;
|
|
}
|
|
|
|
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);
|
|
|
|
free(presskey);
|
|
free(sha);
|
|
return abort;
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
static int passwd_abort_key(uint64_t etime)
|
|
{
|
|
int abort = 0;
|
|
struct {
|
|
char *str;
|
|
u_int len;
|
|
int retry;
|
|
}
|
|
delaykey[] = {
|
|
{ .str = env_get("bootdelaykey"), .retry = 1 },
|
|
{ .str = env_get("bootstopkey"), .retry = 0 },
|
|
};
|
|
|
|
char presskey[MAX_DELAY_STOP_STR];
|
|
u_int presskey_len = 0;
|
|
u_int presskey_max = 0;
|
|
u_int i;
|
|
|
|
# ifdef CONFIG_AUTOBOOT_DELAY_STR
|
|
if (delaykey[0].str == NULL)
|
|
delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
|
|
# endif
|
|
# ifdef CONFIG_AUTOBOOT_STOP_STR
|
|
if (delaykey[1].str == NULL)
|
|
delaykey[1].str = CONFIG_AUTOBOOT_STOP_STR;
|
|
# 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>\n",
|
|
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\n",
|
|
delaykey[i].retry ? "delay" :
|
|
"stop");
|
|
|
|
/* don't retry auto boot */
|
|
if (!delaykey[i].retry)
|
|
bootretry_dont_retry();
|
|
abort = 1;
|
|
}
|
|
}
|
|
} while (!abort && get_ticks() <= etime);
|
|
|
|
return abort;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Watch for 'delay' seconds for autoboot stop or autoboot delay string.
|
|
* returns: 0 - no key string, allow autoboot 1 - got key string, abort
|
|
*/
|
|
static int abortboot_key_sequence(int bootdelay)
|
|
{
|
|
int abort;
|
|
uint64_t etime = endtick(bootdelay);
|
|
|
|
# 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
|
|
|
|
if (IS_ENABLED(CONFIG_AUTOBOOT_ENCRYPTION))
|
|
abort = passwd_abort_sha256(etime);
|
|
else
|
|
abort = passwd_abort_key(etime);
|
|
if (!abort)
|
|
debug_bootkeys("key timeout\n");
|
|
|
|
return abort;
|
|
}
|
|
|
|
static int abortboot_single_key(int bootdelay)
|
|
{
|
|
int abort = 0;
|
|
unsigned long ts;
|
|
|
|
printf("Hit any key to stop autoboot: %2d ", bootdelay);
|
|
|
|
/*
|
|
* Check if key already pressed
|
|
*/
|
|
if (tstc()) { /* we got a key press */
|
|
(void) getc(); /* consume input */
|
|
puts("\b\b\b 0");
|
|
abort = 1; /* don't auto boot */
|
|
}
|
|
|
|
while ((bootdelay > 0) && (!abort)) {
|
|
--bootdelay;
|
|
/* delay 1000 ms */
|
|
ts = get_timer(0);
|
|
do {
|
|
if (tstc()) { /* we got a key press */
|
|
int key;
|
|
|
|
abort = 1; /* don't auto boot */
|
|
bootdelay = 0; /* no more delay */
|
|
key = getc(); /* consume input */
|
|
if (IS_ENABLED(CONFIG_USE_AUTOBOOT_MENUKEY))
|
|
menukey = key;
|
|
break;
|
|
}
|
|
udelay(10000);
|
|
} while (!abort && get_timer(ts) < 1000);
|
|
|
|
printf("\b\b\b%2d ", bootdelay);
|
|
}
|
|
|
|
putc('\n');
|
|
|
|
return abort;
|
|
}
|
|
|
|
static int abortboot(int bootdelay)
|
|
{
|
|
int abort = 0;
|
|
|
|
if (bootdelay >= 0) {
|
|
if (IS_ENABLED(CONFIG_AUTOBOOT_KEYED))
|
|
abort = abortboot_key_sequence(bootdelay);
|
|
else
|
|
abort = abortboot_single_key(bootdelay);
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && abort)
|
|
gd->flags &= ~GD_FLG_SILENT;
|
|
|
|
return abort;
|
|
}
|
|
|
|
static void process_fdt_options(const void *blob)
|
|
{
|
|
#ifdef CONFIG_SYS_TEXT_BASE
|
|
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)
|
|
env_set_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
|
|
|
|
/* 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)
|
|
env_set_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
|
|
#endif /* CONFIG_SYS_TEXT_BASE */
|
|
}
|
|
|
|
const char *bootdelay_process(void)
|
|
{
|
|
char *s;
|
|
int bootdelay;
|
|
|
|
bootcount_inc();
|
|
|
|
s = env_get("bootdelay");
|
|
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
|
|
|
|
if (IS_ENABLED(CONFIG_OF_CONTROL))
|
|
bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
|
|
bootdelay);
|
|
|
|
debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
|
|
|
|
if (IS_ENABLED(CONFIG_AUTOBOOT_MENU_SHOW))
|
|
bootdelay = menu_show(bootdelay);
|
|
bootretry_init_cmd_timeout();
|
|
|
|
#ifdef CONFIG_POST
|
|
if (gd->flags & GD_FLG_POSTFAIL) {
|
|
s = env_get("failbootcmd");
|
|
} else
|
|
#endif /* CONFIG_POST */
|
|
if (bootcount_error())
|
|
s = env_get("altbootcmd");
|
|
else
|
|
s = env_get("bootcmd");
|
|
|
|
if (IS_ENABLED(CONFIG_OF_CONTROL))
|
|
process_fdt_options(gd->fdt_blob);
|
|
stored_bootdelay = bootdelay;
|
|
|
|
return s;
|
|
}
|
|
|
|
void autoboot_command(const char *s)
|
|
{
|
|
debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
|
|
|
|
if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
|
|
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 */
|
|
|
|
run_command_list(s, -1, 0);
|
|
|
|
if (lock)
|
|
disable_ctrlc(prev); /* restore Ctrl-C checking */
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_USE_AUTOBOOT_MENUKEY) &&
|
|
menukey == AUTOBOOT_MENUKEY) {
|
|
s = env_get("menucmd");
|
|
if (s)
|
|
run_command_list(s, -1, 0);
|
|
}
|
|
}
|