Blame view

common/env_common.c 6.16 KB
05706fddd   wdenk   Initial revision
1
  /*
ea882baf9   Wolfgang Denk   New implementatio...
2
   * (C) Copyright 2000-2010
05706fddd   wdenk   Initial revision
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>
ea882baf9   Wolfgang Denk   New implementatio...
7
   *
3765b3e7b   Wolfgang Denk   Coding Style clea...
8
   * SPDX-License-Identifier:	GPL-2.0+
05706fddd   wdenk   Initial revision
9
10
11
12
13
   */
  
  #include <common.h>
  #include <command.h>
  #include <environment.h>
05706fddd   wdenk   Initial revision
14
  #include <linux/stddef.h>
ea882baf9   Wolfgang Denk   New implementatio...
15
16
  #include <search.h>
  #include <errno.h>
05706fddd   wdenk   Initial revision
17
  #include <malloc.h>
d87080b72   Wolfgang Denk   GCC-4.x fixes: cl...
18
  DECLARE_GLOBAL_DATA_PTR;
05706fddd   wdenk   Initial revision
19
20
21
  /************************************************************************
   * Default settings to be used when no valid environment is found
   */
ddd8418f7   Joe Hershberger   env: cosmetic: Co...
22
  #include <env_default.h>
05706fddd   wdenk   Initial revision
23

c5983592e   Gerlando Falauto   env: add check/ap...
24
  struct hsearch_data env_htab = {
2598090b7   Joe Hershberger   env: Add environm...
25
  	.change_ok = env_flags_validate,
c5983592e   Gerlando Falauto   env: add check/ap...
26
  };
2eb1573f0   Mike Frysinger   hashtable: drop a...
27

0b7df6565   Jeroen Hofstee   common: env_commo...
28
  __weak uchar env_get_char_spec(int index)
bf95df44f   Igor Grinberg   env: factor out t...
29
30
31
  {
  	return *((uchar *)(gd->env_addr + index));
  }
bf95df44f   Igor Grinberg   env: factor out t...
32

27aafe988   Igor Grinberg   env: clean env_co...
33
  static uchar env_get_char_init(int index)
05706fddd   wdenk   Initial revision
34
  {
05706fddd   wdenk   Initial revision
35
36
  	/* if crc was bad, use the default environment */
  	if (gd->env_valid)
27aafe988   Igor Grinberg   env: clean env_co...
37
  		return env_get_char_spec(index);
ea882baf9   Wolfgang Denk   New implementatio...
38
  	else
27aafe988   Igor Grinberg   env: clean env_co...
39
  		return default_environment[index];
05706fddd   wdenk   Initial revision
40
  }
27aafe988   Igor Grinberg   env: clean env_co...
41
  uchar env_get_char_memory(int index)
05706fddd   wdenk   Initial revision
42
  {
ea882baf9   Wolfgang Denk   New implementatio...
43
  	return *env_get_addr(index);
05706fddd   wdenk   Initial revision
44
  }
27aafe988   Igor Grinberg   env: clean env_co...
45
  uchar env_get_char(int index)
b502611b5   Joakim Tjernlund   Change env_get_ch...
46
  {
b502611b5   Joakim Tjernlund   Change env_get_ch...
47
48
  	/* if relocated to RAM */
  	if (gd->flags & GD_FLG_RELOC)
27aafe988   Igor Grinberg   env: clean env_co...
49
  		return env_get_char_memory(index);
b502611b5   Joakim Tjernlund   Change env_get_ch...
50
  	else
27aafe988   Igor Grinberg   env: clean env_co...
51
  		return env_get_char_init(index);
b502611b5   Joakim Tjernlund   Change env_get_ch...
52
  }
27aafe988   Igor Grinberg   env: clean env_co...
53
  const uchar *env_get_addr(int index)
05706fddd   wdenk   Initial revision
54
  {
ea882baf9   Wolfgang Denk   New implementatio...
55
56
57
58
  	if (gd->env_valid)
  		return (uchar *)(gd->env_addr + index);
  	else
  		return &default_environment[index];
05706fddd   wdenk   Initial revision
59
  }
ec8a252cd   Joe Hershberger   env: Use getenv_y...
60
61
62
63
64
65
66
67
68
69
70
71
72
  /*
   * 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;
  }
267541f77   Joe Hershberger   env: Add support ...
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  /*
   * 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;
  }
ea882baf9   Wolfgang Denk   New implementatio...
90
  void set_default_env(const char *s)
5bb12dbd7   Harald Welte   Remove code dupli...
91
  {
c4e0057fa   Joe Hershberger   env: Refactor do_...
92
  	int flags = 0;
5bb12dbd7   Harald Welte   Remove code dupli...
93
  	if (sizeof(default_environment) > ENV_SIZE) {
ea882baf9   Wolfgang Denk   New implementatio...
94
95
96
  		puts("*** Error - default environment is too large
  
  ");
5bb12dbd7   Harald Welte   Remove code dupli...
97
98
  		return;
  	}
ea882baf9   Wolfgang Denk   New implementatio...
99
100
101
102
103
104
  	if (s) {
  		if (*s == '!') {
  			printf("*** Warning - %s, "
  				"using default environment
  
  ",
27aafe988   Igor Grinberg   env: clean env_co...
105
  				s + 1);
ea882baf9   Wolfgang Denk   New implementatio...
106
  		} else {
c4e0057fa   Joe Hershberger   env: Refactor do_...
107
  			flags = H_INTERACTIVE;
ea882baf9   Wolfgang Denk   New implementatio...
108
109
110
111
112
113
114
  			puts(s);
  		}
  	} else {
  		puts("Using default environment
  
  ");
  	}
2eb1573f0   Mike Frysinger   hashtable: drop a...
115
  	if (himport_r(&env_htab, (char *)default_environment,
ecd1446fe   Alexander Holler   Add option -r to ...
116
  			sizeof(default_environment), '\0', flags, 0,
c4e0057fa   Joe Hershberger   env: Refactor do_...
117
  			0, NULL) == 0)
ea882baf9   Wolfgang Denk   New implementatio...
118
119
  		error("Environment import failed: errno = %d
  ", errno);
27aafe988   Igor Grinberg   env: clean env_co...
120

ea882baf9   Wolfgang Denk   New implementatio...
121
  	gd->flags |= GD_FLG_ENV_READY;
5bb12dbd7   Harald Welte   Remove code dupli...
122
  }
b64b7c3df   Gerlando Falauto   env: make "env de...
123
124
125
126
127
128
129
130
131
  
  /* [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,
c4e0057fa   Joe Hershberger   env: Refactor do_...
132
  				sizeof(default_environment), '\0',
ecd1446fe   Alexander Holler   Add option -r to ...
133
  				H_NOCLEAR | H_INTERACTIVE, 0, nvars, vars);
b64b7c3df   Gerlando Falauto   env: make "env de...
134
  }
a4223b746   Marek Vasut   env: Implement su...
135
136
137
138
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
  #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
ea882baf9   Wolfgang Denk   New implementatio...
180
181
182
183
184
  /*
   * 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)
05706fddd   wdenk   Initial revision
185
  {
ea882baf9   Wolfgang Denk   New implementatio...
186
  	env_t *ep = (env_t *)buf;
a4223b746   Marek Vasut   env: Implement su...
187
  	int ret;
05706fddd   wdenk   Initial revision
188

ea882baf9   Wolfgang Denk   New implementatio...
189
190
191
192
193
194
195
196
197
198
  	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;
  		}
  	}
a4223b746   Marek Vasut   env: Implement su...
199
200
201
202
203
204
205
206
  	/* Decrypt the env if desired. */
  	ret = env_aes_cbc_crypt(ep, 0);
  	if (ret) {
  		error("Failed to decrypt env!
  ");
  		set_default_env("!import failed");
  		return ret;
  	}
ecd1446fe   Alexander Holler   Add option -r to ...
207
  	if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0, 0,
c4e0057fa   Joe Hershberger   env: Refactor do_...
208
  			0, NULL)) {
ea882baf9   Wolfgang Denk   New implementatio...
209
210
211
  		gd->flags |= GD_FLG_ENV_READY;
  		return 1;
  	}
05706fddd   wdenk   Initial revision
212

ea882baf9   Wolfgang Denk   New implementatio...
213
214
215
216
217
218
219
  	error("Cannot import environment: errno = %d
  ", errno);
  
  	set_default_env("!import failed");
  
  	return 0;
  }
7ce1526ed   Marek Vasut   env: Add env_expo...
220
221
222
223
224
  /* Emport the environment and generate CRC for it. */
  int env_export(env_t *env_out)
  {
  	char *res;
  	ssize_t	len;
a4223b746   Marek Vasut   env: Implement su...
225
  	int ret;
7ce1526ed   Marek Vasut   env: Add env_expo...
226
227
228
229
230
231
232
233
  
  	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
  ", errno);
  		return 1;
  	}
a4223b746   Marek Vasut   env: Implement su...
234
235
236
237
238
  
  	/* Encrypt the env if desired. */
  	ret = env_aes_cbc_crypt(env_out, 1);
  	if (ret)
  		return ret;
7ce1526ed   Marek Vasut   env: Add env_expo...
239
240
241
242
  	env_out->crc = crc32(0, env_out->data, ENV_SIZE);
  
  	return 0;
  }
27aafe988   Igor Grinberg   env: clean env_co...
243
  void env_relocate(void)
ea882baf9   Wolfgang Denk   New implementatio...
244
  {
2e5167cca   Wolfgang Denk   Replace CONFIG_RE...
245
  #if defined(CONFIG_NEEDS_MANUAL_RELOC)
60f7da1f4   Heiko Schocher   env: fix cmd_env_...
246
  	env_reloc();
7afcf3a55   Joe Hershberger   env: Refactor app...
247
  	env_htab.change_ok += gd->reloc_off;
60f7da1f4   Heiko Schocher   env: fix cmd_env_...
248
  #endif
05706fddd   wdenk   Initial revision
249
  	if (gd->env_valid == 0) {
7ac2fe2da   Ilya Yanok   OMAP: networking ...
250
251
  #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)
  		/* Environment not changable */
ea882baf9   Wolfgang Denk   New implementatio...
252
  		set_default_env(NULL);
05706fddd   wdenk   Initial revision
253
  #else
770605e4f   Simon Glass   bootstage: Replac...
254
  		bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM);
ea882baf9   Wolfgang Denk   New implementatio...
255
  		set_default_env("!bad CRC");
d259079d6   Lei Wen   env: don't set to...
256
  #endif
ea882baf9   Wolfgang Denk   New implementatio...
257
  	} else {
27aafe988   Igor Grinberg   env: clean env_co...
258
  		env_relocate_spec();
05706fddd   wdenk   Initial revision
259
  	}
05706fddd   wdenk   Initial revision
260
  }
04a85b3b3   wdenk   * Patches by Pant...
261

7ac2fe2da   Ilya Yanok   OMAP: networking ...
262
  #if defined(CONFIG_AUTO_COMPLETE) && !defined(CONFIG_SPL_BUILD)
04a85b3b3   wdenk   * Patches by Pant...
263
264
  int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf)
  {
560d424b6   Mike Frysinger   env: re-add suppo...
265
266
  	ENTRY *match;
  	int found, idx;
04a85b3b3   wdenk   * Patches by Pant...
267

560d424b6   Mike Frysinger   env: re-add suppo...
268
  	idx = 0;
04a85b3b3   wdenk   * Patches by Pant...
269
270
  	found = 0;
  	cmdv[0] = NULL;
560d424b6   Mike Frysinger   env: re-add suppo...
271
272
  	while ((idx = hmatch_r(var, idx, &match, &env_htab))) {
  		int vallen = strlen(match->key) + 1;
04a85b3b3   wdenk   * Patches by Pant...
273

560d424b6   Mike Frysinger   env: re-add suppo...
274
  		if (found >= maxv - 2 || bufsz < vallen)
04a85b3b3   wdenk   * Patches by Pant...
275
  			break;
560d424b6   Mike Frysinger   env: re-add suppo...
276

04a85b3b3   wdenk   * Patches by Pant...
277
  		cmdv[found++] = buf;
560d424b6   Mike Frysinger   env: re-add suppo...
278
279
280
  		memcpy(buf, match->key, vallen);
  		buf += vallen;
  		bufsz -= vallen;
04a85b3b3   wdenk   * Patches by Pant...
281
  	}
560d424b6   Mike Frysinger   env: re-add suppo...
282
283
284
285
  	qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar);
  
  	if (idx)
  		cmdv[found++] = "...";
27aafe988   Igor Grinberg   env: clean env_co...
286

04a85b3b3   wdenk   * Patches by Pant...
287
288
289
290
  	cmdv[found] = NULL;
  	return found;
  }
  #endif