X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=env%2Fcommon.c;h=088b2aebb42c531b3a026320e60a502d250342ba;hb=1b6ae82a5abb4cbedb0d6cb262526173f4efa486;hp=70715bb6e7564554c233ca3b9e08b928c7bf3925;hpb=74d90d17eebfeeefd91776e3deb7901c122bef7f;p=oweals%2Fu-boot.git diff --git a/env/common.c b/env/common.c index 70715bb6e7..088b2aebb4 100644 --- a/env/common.c +++ b/env/common.c @@ -1,20 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2000-2010 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH * Andreas Heppel - * - * SPDX-License-Identifier: GPL-2.0+ */ #include +#include #include -#include +#include +#include +#include +#include #include #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -59,32 +63,29 @@ char *env_get_default(const char *name) return ret_val; } -void set_default_env(const char *s) +void env_set_default(const char *s, int flags) { - int flags = 0; - if (sizeof(default_environment) > ENV_SIZE) { puts("*** Error - default environment is too large\n\n"); return; } if (s) { - if (*s == '!') { + if ((flags & H_INTERACTIVE) == 0) { printf("*** Warning - %s, " - "using default environment\n\n", - s + 1); + "using default environment\n\n", s); } else { - flags = H_INTERACTIVE; puts(s); } } else { - puts("Using default environment\n\n"); + debug("Using default environment\n"); } if (himport_r(&env_htab, (char *)default_environment, sizeof(default_environment), '\0', flags, 0, 0, NULL) == 0) - pr_err("Environment import failed: errno = %d\n", errno); + pr_err("## Error: Environment import failed: errno = %d\n", + errno); gd->flags |= GD_FLG_ENV_READY; gd->flags |= GD_FLG_ENV_DEFAULT; @@ -92,62 +93,17 @@ void set_default_env(const char *s) /* [re]set individual variables to their value in the default environment */ -int set_default_vars(int nvars, char * const vars[]) +int env_set_default_vars(int nvars, char * const vars[], int flags) { /* * Special use-case: import from default environment * (and use \0 as a separator) */ + flags |= H_NOCLEAR; return himport_r(&env_htab, (const char *)default_environment, sizeof(default_environment), '\0', - H_NOCLEAR | H_INTERACTIVE, 0, nvars, vars); -} - -#ifdef CONFIG_ENV_AES -#include -/** - * env_aes_cbc_get_key() - Get AES-128-CBC key for the environment - * - * This function shall return 16-byte array containing AES-128 key used - * to encrypt and decrypt the environment. This function must be overridden - * by the implementer as otherwise the environment encryption will not - * work. - */ -__weak uint8_t *env_aes_cbc_get_key(void) -{ - return NULL; -} - -static int env_aes_cbc_crypt(env_t *env, const int enc) -{ - unsigned char *data = env->data; - uint8_t *key; - uint8_t key_exp[AES_EXPAND_KEY_LENGTH]; - uint32_t aes_blocks; - - key = env_aes_cbc_get_key(); - if (!key) - return -EINVAL; - - /* First we expand the key. */ - aes_expand_key(key, key_exp); - - /* Calculate the number of AES blocks to encrypt. */ - aes_blocks = ENV_SIZE / AES_KEY_LENGTH; - - if (enc) - aes_cbc_encrypt_blocks(key_exp, data, data, aes_blocks); - else - aes_cbc_decrypt_blocks(key_exp, data, data, aes_blocks); - - return 0; -} -#else -static inline int env_aes_cbc_crypt(env_t *env, const int enc) -{ - return 0; + flags, 0, nvars, vars); } -#endif /* * Check if CRC is valid and (if yes) import the environment. @@ -156,7 +112,6 @@ static inline int env_aes_cbc_crypt(env_t *env, const int enc) int env_import(const char *buf, int check) { env_t *ep = (env_t *)buf; - int ret; if (check) { uint32_t crc; @@ -164,36 +119,29 @@ int env_import(const char *buf, int check) memcpy(&crc, &ep->crc, sizeof(crc)); if (crc32(0, ep->data, ENV_SIZE) != crc) { - set_default_env("!bad CRC"); - return 0; + env_set_default("bad CRC", 0); + return -ENOMSG; /* needed for env_load() */ } } - /* Decrypt the env if desired. */ - ret = env_aes_cbc_crypt(ep, 0); - if (ret) { - pr_err("Failed to decrypt env!\n"); - set_default_env("!import failed"); - return ret; - } - if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0, 0, 0, NULL)) { gd->flags |= GD_FLG_ENV_READY; - return 1; + return 0; } pr_err("Cannot import environment: errno = %d\n", errno); - set_default_env("!import failed"); + env_set_default("import failed", 0); - return 0; + return -EIO; } #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT static unsigned char env_flags; -int env_import_redund(const char *buf1, const char *buf2) +int env_import_redund(const char *buf1, int buf1_read_fail, + const char *buf2, int buf2_read_fail) { int crc1_ok, crc2_ok; env_t *ep, *tmp_env1, *tmp_env2; @@ -201,14 +149,32 @@ int env_import_redund(const char *buf1, const char *buf2) tmp_env1 = (env_t *)buf1; tmp_env2 = (env_t *)buf2; + if (buf1_read_fail && buf2_read_fail) { + puts("*** Error - No Valid Environment Area found\n"); + } else if (buf1_read_fail || buf2_read_fail) { + puts("*** Warning - some problems detected "); + puts("reading environment; recovered successfully\n"); + } + + if (buf1_read_fail && buf2_read_fail) { + env_set_default("bad env area", 0); + return -EIO; + } else if (!buf1_read_fail && buf2_read_fail) { + gd->env_valid = ENV_VALID; + return env_import((char *)tmp_env1, 1); + } else if (buf1_read_fail && !buf2_read_fail) { + gd->env_valid = ENV_REDUND; + return env_import((char *)tmp_env2, 1); + } + crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc; crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc; if (!crc1_ok && !crc2_ok) { - set_default_env("!bad CRC"); - return 0; + env_set_default("bad CRC", 0); + return -ENOMSG; /* needed for env_load() */ } else if (crc1_ok && !crc2_ok) { gd->env_valid = ENV_VALID; } else if (!crc1_ok && crc2_ok) { @@ -242,7 +208,6 @@ int env_export(env_t *env_out) { char *res; ssize_t len; - int ret; res = (char *)env_out->data; len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); @@ -251,11 +216,6 @@ int env_export(env_t *env_out) return 1; } - /* Encrypt the env if desired. */ - ret = env_aes_cbc_crypt(env_out, 1); - if (ret) - return ret; - env_out->crc = crc32(0, env_out->data, ENV_SIZE); #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT @@ -269,47 +229,92 @@ void env_relocate(void) { #if defined(CONFIG_NEEDS_MANUAL_RELOC) env_reloc(); + env_fix_drivers(); env_htab.change_ok += gd->reloc_off; #endif if (gd->env_valid == ENV_INVALID) { #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD) /* Environment not changable */ - set_default_env(NULL); + env_set_default(NULL, 0); #else bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM); - set_default_env("!bad CRC"); + env_set_default("bad CRC", 0); #endif } else { env_load(); } } -#if defined(CONFIG_AUTO_COMPLETE) && !defined(CONFIG_SPL_BUILD) -int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf) +#ifdef CONFIG_AUTO_COMPLETE +int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf, + bool dollar_comp) { - ENTRY *match; + struct env_entry *match; int found, idx; + if (dollar_comp) { + /* + * When doing $ completion, the first character should + * obviously be a '$'. + */ + if (var[0] != '$') + return 0; + + var++; + + /* + * The second one, if present, should be a '{', as some + * configuration of the u-boot shell expand ${var} but not + * $var. + */ + if (var[0] == '{') + var++; + else if (var[0] != '\0') + return 0; + } + idx = 0; found = 0; cmdv[0] = NULL; + while ((idx = hmatch_r(var, idx, &match, &env_htab))) { int vallen = strlen(match->key) + 1; - if (found >= maxv - 2 || bufsz < vallen) + if (found >= maxv - 2 || + bufsz < vallen + (dollar_comp ? 3 : 0)) break; cmdv[found++] = buf; + + /* Add the '${' prefix to each var when doing $ completion. */ + if (dollar_comp) { + strcpy(buf, "${"); + buf += 2; + bufsz -= 3; + } + memcpy(buf, match->key, vallen); buf += vallen; bufsz -= vallen; + + if (dollar_comp) { + /* + * This one is a bit odd: vallen already contains the + * '\0' character but we need to add the '}' suffix, + * hence the buf - 1 here. strcpy() will add the '\0' + * character just after '}'. buf is then incremented + * to account for the extra '}' we just added. + */ + strcpy(buf - 1, "}"); + buf++; + } } qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar); if (idx) - cmdv[found++] = "..."; + cmdv[found++] = dollar_comp ? "${...}" : "..."; cmdv[found] = NULL; return found;