Merge tag 'efi-2022-01-rc1' of https://source.denx.de/u-boot/custodians/u-boot-efi
[platform/kernel/u-boot.git] / env / common.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000-2010
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  *
6  * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
7  * Andreas Heppel <aheppel@sysgo.de>
8  */
9
10 #include <common.h>
11 #include <bootstage.h>
12 #include <command.h>
13 #include <env.h>
14 #include <env_internal.h>
15 #include <log.h>
16 #include <sort.h>
17 #include <asm/global_data.h>
18 #include <linux/stddef.h>
19 #include <search.h>
20 #include <errno.h>
21 #include <malloc.h>
22 #include <u-boot/crc.h>
23 #include <dm/ofnode.h>
24 #include <net.h>
25 #include <watchdog.h>
26
27 DECLARE_GLOBAL_DATA_PTR;
28
29 /************************************************************************
30  * Default settings to be used when no valid environment is found
31  */
32 #include <env_default.h>
33
34 struct hsearch_data env_htab = {
35         .change_ok = env_flags_validate,
36 };
37
38 /*
39  * This env_set() function is defined in cmd/nvedit.c, since it calls
40  * _do_env_set(), whis is a static function in that file.
41  *
42  * int env_set(const char *varname, const char *varvalue);
43  */
44
45 /**
46  * Set an environment variable to an integer value
47  *
48  * @param varname       Environment variable to set
49  * @param value         Value to set it to
50  * @return 0 if ok, 1 on error
51  */
52 int env_set_ulong(const char *varname, ulong value)
53 {
54         /* TODO: this should be unsigned */
55         char *str = simple_itoa(value);
56
57         return env_set(varname, str);
58 }
59
60 /**
61  * Set an environment variable to an value in hex
62  *
63  * @param varname       Environment variable to set
64  * @param value         Value to set it to
65  * @return 0 if ok, 1 on error
66  */
67 int env_set_hex(const char *varname, ulong value)
68 {
69         char str[17];
70
71         sprintf(str, "%lx", value);
72         return env_set(varname, str);
73 }
74
75 ulong env_get_hex(const char *varname, ulong default_val)
76 {
77         const char *s;
78         ulong value;
79         char *endp;
80
81         s = env_get(varname);
82         if (s)
83                 value = hextoul(s, &endp);
84         if (!s || endp == s)
85                 return default_val;
86
87         return value;
88 }
89
90 int eth_env_get_enetaddr(const char *name, uint8_t *enetaddr)
91 {
92         string_to_enetaddr(env_get(name), enetaddr);
93         return is_valid_ethaddr(enetaddr);
94 }
95
96 int eth_env_set_enetaddr(const char *name, const uint8_t *enetaddr)
97 {
98         char buf[ARP_HLEN_ASCII + 1];
99
100         if (eth_env_get_enetaddr(name, (uint8_t *)buf))
101                 return -EEXIST;
102
103         sprintf(buf, "%pM", enetaddr);
104
105         return env_set(name, buf);
106 }
107
108 /*
109  * Look up variable from environment,
110  * return address of storage for that variable,
111  * or NULL if not found
112  */
113 char *env_get(const char *name)
114 {
115         if (gd->flags & GD_FLG_ENV_READY) { /* after import into hashtable */
116                 struct env_entry e, *ep;
117
118                 WATCHDOG_RESET();
119
120                 e.key   = name;
121                 e.data  = NULL;
122                 hsearch_r(e, ENV_FIND, &ep, &env_htab, 0);
123
124                 return ep ? ep->data : NULL;
125         }
126
127         /* restricted capabilities before import */
128         if (env_get_f(name, (char *)(gd->env_buf), sizeof(gd->env_buf)) > 0)
129                 return (char *)(gd->env_buf);
130
131         return NULL;
132 }
133
134 /*
135  * Like env_get, but prints an error if envvar isn't defined in the
136  * environment.  It always returns what env_get does, so it can be used in
137  * place of env_get without changing error handling otherwise.
138  */
139 char *from_env(const char *envvar)
140 {
141         char *ret;
142
143         ret = env_get(envvar);
144
145         if (!ret)
146                 printf("missing environment variable: %s\n", envvar);
147
148         return ret;
149 }
150
151 /*
152  * Look up variable from environment for restricted C runtime env.
153  */
154 int env_get_f(const char *name, char *buf, unsigned len)
155 {
156         const char *env, *p, *end;
157         size_t name_len;
158
159         if (name == NULL || *name == '\0')
160                 return -1;
161
162         name_len = strlen(name);
163
164         if (gd->env_valid == ENV_INVALID)
165                 env = (const char *)default_environment;
166         else
167                 env = (const char *)gd->env_addr;
168
169         for (p = env; *p != '\0'; p = end + 1) {
170                 const char *value;
171                 unsigned res;
172
173                 for (end = p; *end != '\0'; ++end)
174                         if (end - env >= CONFIG_ENV_SIZE)
175                                 return -1;
176
177                 if (strncmp(name, p, name_len) || p[name_len] != '=')
178                         continue;
179                 value = &p[name_len + 1];
180
181                 res = end - value;
182                 memcpy(buf, value, min(len, res + 1));
183
184                 if (len <= res) {
185                         buf[len - 1] = '\0';
186                         printf("env_buf [%u bytes] too small for value of \"%s\"\n",
187                                len, name);
188                 }
189
190                 return res;
191         }
192
193         return -1;
194 }
195
196 /**
197  * Decode the integer value of an environment variable and return it.
198  *
199  * @param name          Name of environment variable
200  * @param base          Number base to use (normally 10, or 16 for hex)
201  * @param default_val   Default value to return if the variable is not
202  *                      found
203  * @return the decoded value, or default_val if not found
204  */
205 ulong env_get_ulong(const char *name, int base, ulong default_val)
206 {
207         /*
208          * We can use env_get() here, even before relocation, since the
209          * environment variable value is an integer and thus short.
210          */
211         const char *str = env_get(name);
212
213         return str ? simple_strtoul(str, NULL, base) : default_val;
214 }
215
216 /*
217  * Read an environment variable as a boolean
218  * Return -1 if variable does not exist (default to true)
219  */
220 int env_get_yesno(const char *var)
221 {
222         char *s = env_get(var);
223
224         if (s == NULL)
225                 return -1;
226         return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ?
227                 1 : 0;
228 }
229
230 /*
231  * Look up the variable from the default environment
232  */
233 char *env_get_default(const char *name)
234 {
235         char *ret_val;
236         unsigned long really_valid = gd->env_valid;
237         unsigned long real_gd_flags = gd->flags;
238
239         /* Pretend that the image is bad. */
240         gd->flags &= ~GD_FLG_ENV_READY;
241         gd->env_valid = ENV_INVALID;
242         ret_val = env_get(name);
243         gd->env_valid = really_valid;
244         gd->flags = real_gd_flags;
245         return ret_val;
246 }
247
248 void env_set_default(const char *s, int flags)
249 {
250         if (sizeof(default_environment) > ENV_SIZE) {
251                 puts("*** Error - default environment is too large\n\n");
252                 return;
253         }
254
255         if (s) {
256                 if ((flags & H_INTERACTIVE) == 0) {
257                         printf("*** Warning - %s, "
258                                 "using default environment\n\n", s);
259                 } else {
260                         puts(s);
261                 }
262         } else {
263                 debug("Using default environment\n");
264         }
265
266         flags |= H_DEFAULT;
267         if (himport_r(&env_htab, (char *)default_environment,
268                         sizeof(default_environment), '\0', flags, 0,
269                         0, NULL) == 0)
270                 pr_err("## Error: Environment import failed: errno = %d\n",
271                        errno);
272
273         gd->flags |= GD_FLG_ENV_READY;
274         gd->flags |= GD_FLG_ENV_DEFAULT;
275 }
276
277
278 /* [re]set individual variables to their value in the default environment */
279 int env_set_default_vars(int nvars, char * const vars[], int flags)
280 {
281         /*
282          * Special use-case: import from default environment
283          * (and use \0 as a separator)
284          */
285         flags |= H_NOCLEAR | H_DEFAULT;
286         return himport_r(&env_htab, (const char *)default_environment,
287                                 sizeof(default_environment), '\0',
288                                 flags, 0, nvars, vars);
289 }
290
291 /*
292  * Check if CRC is valid and (if yes) import the environment.
293  * Note that "buf" may or may not be aligned.
294  */
295 int env_import(const char *buf, int check, int flags)
296 {
297         env_t *ep = (env_t *)buf;
298
299         if (check) {
300                 uint32_t crc;
301
302                 memcpy(&crc, &ep->crc, sizeof(crc));
303
304                 if (crc32(0, ep->data, ENV_SIZE) != crc) {
305                         env_set_default("bad CRC", 0);
306                         return -ENOMSG; /* needed for env_load() */
307                 }
308         }
309
310         if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', flags, 0,
311                         0, NULL)) {
312                 gd->flags |= GD_FLG_ENV_READY;
313                 return 0;
314         }
315
316         pr_err("Cannot import environment: errno = %d\n", errno);
317
318         env_set_default("import failed", 0);
319
320         return -EIO;
321 }
322
323 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
324 static unsigned char env_flags;
325
326 int env_check_redund(const char *buf1, int buf1_read_fail,
327                      const char *buf2, int buf2_read_fail)
328 {
329         int crc1_ok = 0, crc2_ok = 0;
330         env_t *tmp_env1, *tmp_env2;
331
332         tmp_env1 = (env_t *)buf1;
333         tmp_env2 = (env_t *)buf2;
334
335         if (buf1_read_fail && buf2_read_fail) {
336                 puts("*** Error - No Valid Environment Area found\n");
337                 return -EIO;
338         } else if (buf1_read_fail || buf2_read_fail) {
339                 puts("*** Warning - some problems detected ");
340                 puts("reading environment; recovered successfully\n");
341         }
342
343         if (!buf1_read_fail)
344                 crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) ==
345                                 tmp_env1->crc;
346         if (!buf2_read_fail)
347                 crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) ==
348                                 tmp_env2->crc;
349
350         if (!crc1_ok && !crc2_ok) {
351                 return -ENOMSG; /* needed for env_load() */
352         } else if (crc1_ok && !crc2_ok) {
353                 gd->env_valid = ENV_VALID;
354         } else if (!crc1_ok && crc2_ok) {
355                 gd->env_valid = ENV_REDUND;
356         } else {
357                 /* both ok - check serial */
358                 if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
359                         gd->env_valid = ENV_REDUND;
360                 else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
361                         gd->env_valid = ENV_VALID;
362                 else if (tmp_env1->flags > tmp_env2->flags)
363                         gd->env_valid = ENV_VALID;
364                 else if (tmp_env2->flags > tmp_env1->flags)
365                         gd->env_valid = ENV_REDUND;
366                 else /* flags are equal - almost impossible */
367                         gd->env_valid = ENV_VALID;
368         }
369
370         return 0;
371 }
372
373 int env_import_redund(const char *buf1, int buf1_read_fail,
374                       const char *buf2, int buf2_read_fail,
375                       int flags)
376 {
377         env_t *ep;
378         int ret;
379
380         ret = env_check_redund(buf1, buf1_read_fail, buf2, buf2_read_fail);
381
382         if (ret == -EIO) {
383                 env_set_default("bad env area", 0);
384                 return -EIO;
385         } else if (ret == -ENOMSG) {
386                 env_set_default("bad CRC", 0);
387                 return -ENOMSG;
388         }
389
390         if (gd->env_valid == ENV_VALID)
391                 ep = (env_t *)buf1;
392         else
393                 ep = (env_t *)buf2;
394
395         env_flags = ep->flags;
396
397         return env_import((char *)ep, 0, flags);
398 }
399 #endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */
400
401 /* Export the environment and generate CRC for it. */
402 int env_export(env_t *env_out)
403 {
404         char *res;
405         ssize_t len;
406
407         res = (char *)env_out->data;
408         len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
409         if (len < 0) {
410                 pr_err("Cannot export environment: errno = %d\n", errno);
411                 return 1;
412         }
413
414         env_out->crc = crc32(0, env_out->data, ENV_SIZE);
415
416 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
417         env_out->flags = ++env_flags; /* increase the serial */
418 #endif
419
420         return 0;
421 }
422
423 void env_relocate(void)
424 {
425 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
426         env_reloc();
427         env_fix_drivers();
428         env_htab.change_ok += gd->reloc_off;
429 #endif
430         if (gd->env_valid == ENV_INVALID) {
431 #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)
432                 /* Environment not changable */
433                 env_set_default(NULL, 0);
434 #else
435                 bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM);
436                 env_set_default("bad CRC", 0);
437 #endif
438         } else {
439                 env_load();
440         }
441 }
442
443 #ifdef CONFIG_AUTO_COMPLETE
444 int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf,
445                  bool dollar_comp)
446 {
447         struct env_entry *match;
448         int found, idx;
449
450         if (dollar_comp) {
451                 /*
452                  * When doing $ completion, the first character should
453                  * obviously be a '$'.
454                  */
455                 if (var[0] != '$')
456                         return 0;
457
458                 var++;
459
460                 /*
461                  * The second one, if present, should be a '{', as some
462                  * configuration of the u-boot shell expand ${var} but not
463                  * $var.
464                  */
465                 if (var[0] == '{')
466                         var++;
467                 else if (var[0] != '\0')
468                         return 0;
469         }
470
471         idx = 0;
472         found = 0;
473         cmdv[0] = NULL;
474
475
476         while ((idx = hmatch_r(var, idx, &match, &env_htab))) {
477                 int vallen = strlen(match->key) + 1;
478
479                 if (found >= maxv - 2 ||
480                     bufsz < vallen + (dollar_comp ? 3 : 0))
481                         break;
482
483                 cmdv[found++] = buf;
484
485                 /* Add the '${' prefix to each var when doing $ completion. */
486                 if (dollar_comp) {
487                         strcpy(buf, "${");
488                         buf += 2;
489                         bufsz -= 3;
490                 }
491
492                 memcpy(buf, match->key, vallen);
493                 buf += vallen;
494                 bufsz -= vallen;
495
496                 if (dollar_comp) {
497                         /*
498                          * This one is a bit odd: vallen already contains the
499                          * '\0' character but we need to add the '}' suffix,
500                          * hence the buf - 1 here. strcpy() will add the '\0'
501                          * character just after '}'. buf is then incremented
502                          * to account for the extra '}' we just added.
503                          */
504                         strcpy(buf - 1, "}");
505                         buf++;
506                 }
507         }
508
509         qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar);
510
511         if (idx)
512                 cmdv[found++] = dollar_comp ? "${...}" : "...";
513
514         cmdv[found] = NULL;
515         return found;
516 }
517 #endif
518
519 #ifdef CONFIG_ENV_IMPORT_FDT
520 void env_import_fdt(void)
521 {
522         const char *path;
523         struct ofprop prop;
524         ofnode node;
525         int res;
526
527         path = env_get("env_fdt_path");
528         if (!path || !path[0])
529                 return;
530
531         node = ofnode_path(path);
532         if (!ofnode_valid(node)) {
533                 printf("Warning: device tree node '%s' not found\n", path);
534                 return;
535         }
536
537         for (res = ofnode_get_first_property(node, &prop);
538              !res;
539              res = ofnode_get_next_property(&prop)) {
540                 const char *name, *val;
541
542                 val = ofnode_get_property_by_prop(&prop, &name, NULL);
543                 env_set(name, val);
544         }
545 }
546 #endif