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