env_common.c 6.16 KB
Newer Older
wdenk's avatar
wdenk committed
1
/*
2
 * (C) Copyright 2000-2010
wdenk's avatar
wdenk committed
3 4 5 6
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 * Andreas Heppel <aheppel@sysgo.de>
7
 *
8
 * SPDX-License-Identifier:	GPL-2.0+
wdenk's avatar
wdenk committed
9 10 11 12 13 14
 */

#include <common.h>
#include <command.h>
#include <environment.h>
#include <linux/stddef.h>
15 16
#include <search.h>
#include <errno.h>
wdenk's avatar
wdenk committed
17 18
#include <malloc.h>

19 20
DECLARE_GLOBAL_DATA_PTR;

wdenk's avatar
wdenk committed
21 22 23
/************************************************************************
 * Default settings to be used when no valid environment is found
 */
24
#include <env_default.h>
wdenk's avatar
wdenk committed
25

26
struct hsearch_data env_htab = {
27
	.change_ok = env_flags_validate,
28
};
29

30
__weak uchar env_get_char_spec(int index)
31 32 33 34
{
	return *((uchar *)(gd->env_addr + index));
}

35
static uchar env_get_char_init(int index)
wdenk's avatar
wdenk committed
36 37 38
{
	/* if crc was bad, use the default environment */
	if (gd->env_valid)
39
		return env_get_char_spec(index);
40
	else
41
		return default_environment[index];
wdenk's avatar
wdenk committed
42 43
}

44
uchar env_get_char_memory(int index)
wdenk's avatar
wdenk committed
45
{
46
	return *env_get_addr(index);
wdenk's avatar
wdenk committed
47 48
}

49
uchar env_get_char(int index)
50 51 52
{
	/* if relocated to RAM */
	if (gd->flags & GD_FLG_RELOC)
53
		return env_get_char_memory(index);
54
	else
55
		return env_get_char_init(index);
56 57
}

58
const uchar *env_get_addr(int index)
wdenk's avatar
wdenk committed
59
{
60 61 62 63
	if (gd->env_valid)
		return (uchar *)(gd->env_addr + index);
	else
		return &default_environment[index];
wdenk's avatar
wdenk committed
64 65
}

66 67 68 69 70 71 72 73 74 75 76 77 78 79
/*
 * Read an environment variable as a boolean
 * Return -1 if variable does not exist (default to true)
 */
int getenv_yesno(const char *var)
{
	char *s = getenv(var);

	if (s == NULL)
		return -1;
	return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ?
		1 : 0;
}

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
/*
 * Look up the variable from the default environment
 */
char *getenv_default(const char *name)
{
	char *ret_val;
	unsigned long really_valid = gd->env_valid;
	unsigned long real_gd_flags = gd->flags;

	/* Pretend that the image is bad. */
	gd->flags &= ~GD_FLG_ENV_READY;
	gd->env_valid = 0;
	ret_val = getenv(name);
	gd->env_valid = really_valid;
	gd->flags = real_gd_flags;
	return ret_val;
}

98
void set_default_env(const char *s)
99
{
100 101
	int flags = 0;

102
	if (sizeof(default_environment) > ENV_SIZE) {
103
		puts("*** Error - default environment is too large\n\n");
104 105 106
		return;
	}

107 108 109 110
	if (s) {
		if (*s == '!') {
			printf("*** Warning - %s, "
				"using default environment\n\n",
111
				s + 1);
112
		} else {
113
			flags = H_INTERACTIVE;
114 115 116 117 118 119
			puts(s);
		}
	} else {
		puts("Using default environment\n\n");
	}

120
	if (himport_r(&env_htab, (char *)default_environment,
121
			sizeof(default_environment), '\0', flags, 0,
122
			0, NULL) == 0)
123
		error("Environment import failed: errno = %d\n", errno);
124

125
	gd->flags |= GD_FLG_ENV_READY;
126 127
}

128 129 130 131 132 133 134 135 136

/* [re]set individual variables to their value in the default environment */
int set_default_vars(int nvars, char * const vars[])
{
	/*
	 * Special use-case: import from default environment
	 * (and use \0 as a separator)
	 */
	return himport_r(&env_htab, (const char *)default_environment,
137
				sizeof(default_environment), '\0',
138
				H_NOCLEAR | H_INTERACTIVE, 0, nvars, vars);
139 140
}

141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 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
#ifdef CONFIG_ENV_AES
#include <aes.h>
/**
 * 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 overriden
 * 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;
}
#endif

187 188 189 190 191
/*
 * Check if CRC is valid and (if yes) import the environment.
 * Note that "buf" may or may not be aligned.
 */
int env_import(const char *buf, int check)
wdenk's avatar
wdenk committed
192
{
193
	env_t *ep = (env_t *)buf;
194
	int ret;
wdenk's avatar
wdenk committed
195

196 197 198 199 200 201 202 203 204 205 206
	if (check) {
		uint32_t crc;

		memcpy(&crc, &ep->crc, sizeof(crc));

		if (crc32(0, ep->data, ENV_SIZE) != crc) {
			set_default_env("!bad CRC");
			return 0;
		}
	}

207 208 209 210 211 212 213 214
	/* Decrypt the env if desired. */
	ret = env_aes_cbc_crypt(ep, 0);
	if (ret) {
		error("Failed to decrypt env!\n");
		set_default_env("!import failed");
		return ret;
	}

215
	if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0, 0,
216
			0, NULL)) {
217 218 219
		gd->flags |= GD_FLG_ENV_READY;
		return 1;
	}
wdenk's avatar
wdenk committed
220

221 222 223 224 225 226 227
	error("Cannot import environment: errno = %d\n", errno);

	set_default_env("!import failed");

	return 0;
}

Marek Vasut's avatar
Marek Vasut committed
228 229 230 231 232
/* Emport the environment and generate CRC for it. */
int env_export(env_t *env_out)
{
	char *res;
	ssize_t	len;
233
	int ret;
Marek Vasut's avatar
Marek Vasut committed
234 235 236 237 238 239 240

	res = (char *)env_out->data;
	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
	if (len < 0) {
		error("Cannot export environment: errno = %d\n", errno);
		return 1;
	}
241 242 243 244 245 246

	/* Encrypt the env if desired. */
	ret = env_aes_cbc_crypt(env_out, 1);
	if (ret)
		return ret;

Marek Vasut's avatar
Marek Vasut committed
247 248 249 250 251
	env_out->crc = crc32(0, env_out->data, ENV_SIZE);

	return 0;
}

252
void env_relocate(void)
253
{
254
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
255
	env_reloc();
256
	env_htab.change_ok += gd->reloc_off;
257
#endif
wdenk's avatar
wdenk committed
258
	if (gd->env_valid == 0) {
259 260
#if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)
		/* Environment not changable */
261
		set_default_env(NULL);
wdenk's avatar
wdenk committed
262
#else
263
		bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM);
264
		set_default_env("!bad CRC");
265
#endif
266
	} else {
267
		env_relocate_spec();
wdenk's avatar
wdenk committed
268 269
	}
}
270

271
#if defined(CONFIG_AUTO_COMPLETE) && !defined(CONFIG_SPL_BUILD)
272 273
int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf)
{
274 275
	ENTRY *match;
	int found, idx;
276

277
	idx = 0;
278 279 280
	found = 0;
	cmdv[0] = NULL;

281 282
	while ((idx = hmatch_r(var, idx, &match, &env_htab))) {
		int vallen = strlen(match->key) + 1;
283

284
		if (found >= maxv - 2 || bufsz < vallen)
285
			break;
286

287
		cmdv[found++] = buf;
288 289 290
		memcpy(buf, match->key, vallen);
		buf += vallen;
		bufsz -= vallen;
291 292
	}

293 294 295 296
	qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar);

	if (idx)
		cmdv[found++] = "...";
297

298 299 300 301
	cmdv[found] = NULL;
	return found;
}
#endif