1 /* 2 * (C) Copyright 2000-2010 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com> 6 * Andreas Heppel <aheppel@sysgo.de> 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 #include <common.h> 12 #include <command.h> 13 #include <environment.h> 14 #include <linux/stddef.h> 15 #include <search.h> 16 #include <errno.h> 17 #include <malloc.h> 18 19 DECLARE_GLOBAL_DATA_PTR; 20 21 /************************************************************************ 22 * Default settings to be used when no valid environment is found 23 */ 24 #include <env_default.h> 25 26 struct hsearch_data env_htab = { 27 .change_ok = env_flags_validate, 28 }; 29 30 /* 31 * Read an environment variable as a boolean 32 * Return -1 if variable does not exist (default to true) 33 */ 34 int env_get_yesno(const char *var) 35 { 36 char *s = env_get(var); 37 38 if (s == NULL) 39 return -1; 40 return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ? 41 1 : 0; 42 } 43 44 __weak void board_env_fixup(void) {} 45 46 /* 47 * Look up the variable from the default environment 48 */ 49 char *env_get_default(const char *name) 50 { 51 char *ret_val; 52 unsigned long really_valid = gd->env_valid; 53 unsigned long real_gd_flags = gd->flags; 54 55 /* Pretend that the image is bad. */ 56 gd->flags &= ~GD_FLG_ENV_READY; 57 gd->env_valid = ENV_INVALID; 58 ret_val = env_get(name); 59 gd->env_valid = really_valid; 60 gd->flags = real_gd_flags; 61 return ret_val; 62 } 63 64 void set_default_env(const char *s) 65 { 66 int flags = 0; 67 68 if (sizeof(default_environment) > ENV_SIZE) { 69 puts("*** Error - default environment is too large\n\n"); 70 return; 71 } 72 73 if (s) { 74 if (*s == '!') { 75 printf("*** Warning - %s, " 76 "using default environment\n\n", 77 s + 1); 78 } else { 79 flags = H_INTERACTIVE; 80 puts(s); 81 } 82 } else { 83 puts("Using default environment\n\n"); 84 } 85 86 if (himport_r(&env_htab, (char *)default_environment, 87 sizeof(default_environment), '\0', flags, 0, 88 0, NULL) == 0) 89 pr_err("Environment import failed: errno = %d\n", errno); 90 91 gd->flags |= GD_FLG_ENV_READY; 92 gd->flags |= GD_FLG_ENV_DEFAULT; 93 94 board_env_fixup(); 95 } 96 97 98 /* [re]set individual variables to their value in the default environment */ 99 int set_default_vars(int nvars, char * const vars[]) 100 { 101 /* 102 * Special use-case: import from default environment 103 * (and use \0 as a separator) 104 */ 105 return himport_r(&env_htab, (const char *)default_environment, 106 sizeof(default_environment), '\0', 107 H_NOCLEAR | H_INTERACTIVE, 0, nvars, vars); 108 } 109 110 int set_board_env(const char *vars, int size, int flags, bool ready) 111 { 112 if (himport_r(&env_htab, (char *)vars, size, '\0', 113 flags, 0, 0, NULL) == 0) { 114 pr_err("Environment import failed\n"); 115 return -1; 116 } 117 118 if (ready) { 119 gd->flags |= GD_FLG_ENV_READY; 120 gd->flags |= GD_FLG_ENV_DEFAULT; 121 } 122 123 return 0; 124 } 125 126 #ifdef CONFIG_ENV_AES 127 #include <uboot_aes.h> 128 /** 129 * env_aes_cbc_get_key() - Get AES-128-CBC key for the environment 130 * 131 * This function shall return 16-byte array containing AES-128 key used 132 * to encrypt and decrypt the environment. This function must be overridden 133 * by the implementer as otherwise the environment encryption will not 134 * work. 135 */ 136 __weak uint8_t *env_aes_cbc_get_key(void) 137 { 138 return NULL; 139 } 140 141 static int env_aes_cbc_crypt(env_t *env, const int enc) 142 { 143 unsigned char *data = env->data; 144 uint8_t *key; 145 uint8_t key_exp[AES_EXPAND_KEY_LENGTH]; 146 uint32_t aes_blocks; 147 148 key = env_aes_cbc_get_key(); 149 if (!key) 150 return -EINVAL; 151 152 /* First we expand the key. */ 153 aes_expand_key(key, key_exp); 154 155 /* Calculate the number of AES blocks to encrypt. */ 156 aes_blocks = ENV_SIZE / AES_KEY_LENGTH; 157 158 if (enc) 159 aes_cbc_encrypt_blocks(key_exp, data, data, aes_blocks); 160 else 161 aes_cbc_decrypt_blocks(key_exp, data, data, aes_blocks); 162 163 return 0; 164 } 165 #else 166 static inline int env_aes_cbc_crypt(env_t *env, const int enc) 167 { 168 return 0; 169 } 170 #endif 171 172 /* 173 * Check if CRC is valid and (if yes) import the environment. 174 * Note that "buf" may or may not be aligned. 175 */ 176 int env_import(const char *buf, int check) 177 { 178 env_t *ep = (env_t *)buf; 179 int ret; 180 181 if (check) { 182 uint32_t crc; 183 184 memcpy(&crc, &ep->crc, sizeof(crc)); 185 186 if (crc32(0, ep->data, ENV_SIZE) != crc) { 187 set_default_env("!bad CRC"); 188 return 0; 189 } 190 } 191 192 /* Decrypt the env if desired. */ 193 ret = env_aes_cbc_crypt(ep, 0); 194 if (ret) { 195 pr_err("Failed to decrypt env!\n"); 196 set_default_env("!import failed"); 197 return ret; 198 } 199 200 if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0, 0, 201 0, NULL)) { 202 gd->flags |= GD_FLG_ENV_READY; 203 return 1; 204 } 205 206 pr_err("Cannot import environment: errno = %d\n", errno); 207 208 set_default_env("!import failed"); 209 210 return 0; 211 } 212 213 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT 214 static unsigned char env_flags; 215 216 int env_import_redund(const char *buf1, const char *buf2) 217 { 218 int crc1_ok, crc2_ok; 219 env_t *ep, *tmp_env1, *tmp_env2; 220 221 tmp_env1 = (env_t *)buf1; 222 tmp_env2 = (env_t *)buf2; 223 224 crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == 225 tmp_env1->crc; 226 crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == 227 tmp_env2->crc; 228 229 if (!crc1_ok && !crc2_ok) { 230 set_default_env("!bad CRC"); 231 return 0; 232 } else if (crc1_ok && !crc2_ok) { 233 gd->env_valid = ENV_VALID; 234 } else if (!crc1_ok && crc2_ok) { 235 gd->env_valid = ENV_REDUND; 236 } else { 237 /* both ok - check serial */ 238 if (tmp_env1->flags == 255 && tmp_env2->flags == 0) 239 gd->env_valid = ENV_REDUND; 240 else if (tmp_env2->flags == 255 && tmp_env1->flags == 0) 241 gd->env_valid = ENV_VALID; 242 else if (tmp_env1->flags > tmp_env2->flags) 243 gd->env_valid = ENV_VALID; 244 else if (tmp_env2->flags > tmp_env1->flags) 245 gd->env_valid = ENV_REDUND; 246 else /* flags are equal - almost impossible */ 247 gd->env_valid = ENV_VALID; 248 } 249 250 if (gd->env_valid == ENV_VALID) 251 ep = tmp_env1; 252 else 253 ep = tmp_env2; 254 255 env_flags = ep->flags; 256 return env_import((char *)ep, 0); 257 } 258 #endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */ 259 260 /* Export the environment and generate CRC for it. */ 261 int env_export(env_t *env_out) 262 { 263 char *res; 264 ssize_t len; 265 int ret; 266 267 res = (char *)env_out->data; 268 len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); 269 if (len < 0) { 270 pr_err("Cannot export environment: errno = %d\n", errno); 271 return 1; 272 } 273 274 /* Encrypt the env if desired. */ 275 ret = env_aes_cbc_crypt(env_out, 1); 276 if (ret) 277 return ret; 278 279 env_out->crc = crc32(0, env_out->data, ENV_SIZE); 280 281 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT 282 env_out->flags = ++env_flags; /* increase the serial */ 283 #endif 284 285 return 0; 286 } 287 288 void env_relocate(void) 289 { 290 #if defined(CONFIG_NEEDS_MANUAL_RELOC) 291 env_reloc(); 292 env_htab.change_ok += gd->reloc_off; 293 #endif 294 if (gd->env_valid == ENV_INVALID) { 295 #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD) 296 /* Environment not changable */ 297 set_default_env(NULL); 298 #else 299 bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM); 300 set_default_env("!bad CRC"); 301 #endif 302 } else { 303 env_load(); 304 } 305 } 306 307 #if defined(CONFIG_AUTO_COMPLETE) && !defined(CONFIG_SPL_BUILD) 308 int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf) 309 { 310 ENTRY *match; 311 int found, idx; 312 313 idx = 0; 314 found = 0; 315 cmdv[0] = NULL; 316 317 while ((idx = hmatch_r(var, idx, &match, &env_htab))) { 318 int vallen = strlen(match->key) + 1; 319 320 if (found >= maxv - 2 || bufsz < vallen) 321 break; 322 323 cmdv[found++] = buf; 324 memcpy(buf, match->key, vallen); 325 buf += vallen; 326 bufsz -= vallen; 327 } 328 329 qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar); 330 331 if (idx) 332 cmdv[found++] = "..."; 333 334 cmdv[found] = NULL; 335 return found; 336 } 337 #endif 338