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