]> Git Repo - J-u-boot.git/blob - env/env.c
Merge patch series "FWU: Add support for FWU metadata version 2"
[J-u-boot.git] / env / env.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2017 Google, Inc
4  * Written by Simon Glass <[email protected]>
5  */
6
7 #include <env.h>
8 #include <env_internal.h>
9 #include <log.h>
10 #include <asm/global_data.h>
11 #include <linux/bitops.h>
12 #include <linux/bug.h>
13 #include <linux/errno.h>
14
15 DECLARE_GLOBAL_DATA_PTR;
16
17 static struct env_driver *_env_driver_lookup(enum env_location loc)
18 {
19         struct env_driver *drv;
20         const int n_ents = ll_entry_count(struct env_driver, env_driver);
21         struct env_driver *entry;
22
23         drv = ll_entry_start(struct env_driver, env_driver);
24         for (entry = drv; entry != drv + n_ents; entry++) {
25                 if (loc == entry->location)
26                         return entry;
27         }
28
29         /* Not found */
30         return NULL;
31 }
32
33 static enum env_location env_locations[] = {
34 #ifdef CONFIG_ENV_IS_IN_EEPROM
35         ENVL_EEPROM,
36 #endif
37 #ifdef CONFIG_ENV_IS_IN_EXT4
38         ENVL_EXT4,
39 #endif
40 #ifdef CONFIG_ENV_IS_IN_FAT
41         ENVL_FAT,
42 #endif
43 #ifdef CONFIG_ENV_IS_IN_FLASH
44         ENVL_FLASH,
45 #endif
46 #ifdef CONFIG_ENV_IS_IN_MMC
47         ENVL_MMC,
48 #endif
49 #ifdef CONFIG_ENV_IS_IN_NAND
50         ENVL_NAND,
51 #endif
52 #ifdef CONFIG_ENV_IS_IN_NVRAM
53         ENVL_NVRAM,
54 #endif
55 #ifdef CONFIG_ENV_IS_IN_REMOTE
56         ENVL_REMOTE,
57 #endif
58 #ifdef CONFIG_ENV_IS_IN_SPI_FLASH
59         ENVL_SPI_FLASH,
60 #endif
61 #ifdef CONFIG_ENV_IS_IN_UBI
62         ENVL_UBI,
63 #endif
64 #ifdef CONFIG_ENV_IS_NOWHERE
65         ENVL_NOWHERE,
66 #endif
67 };
68
69 static bool env_has_inited(enum env_location location)
70 {
71         return gd->env_has_init & BIT(location);
72 }
73
74 static void env_set_inited(enum env_location location)
75 {
76         /*
77          * We're using a 32-bits bitmask stored in gd (env_has_init)
78          * using the above enum value as the bit index. We need to
79          * make sure that we're not overflowing it.
80          */
81         BUILD_BUG_ON(ENVL_COUNT > BITS_PER_LONG);
82
83         gd->env_has_init |= BIT(location);
84 }
85
86 /**
87  * arch_env_get_location() - Returns the best env location for an arch
88  * @op: operations performed on the environment
89  * @prio: priority between the multiple environments, 0 being the
90  *        highest priority
91  *
92  * This will return the preferred environment for the given priority.
93  * This is overridable by architectures if they need to and has lower
94  * priority than board side env_get_location() override.
95  *
96  * All implementations are free to use the operation, the priority and
97  * any other data relevant to their choice, but must take into account
98  * the fact that the lowest prority (0) is the most important location
99  * in the system. The following locations should be returned by order
100  * of descending priorities, from the highest to the lowest priority.
101  *
102  * Returns:
103  * an enum env_location value on success, a negative error code otherwise
104  */
105 __weak enum env_location arch_env_get_location(enum env_operation op, int prio)
106 {
107         if (prio >= ARRAY_SIZE(env_locations))
108                 return ENVL_UNKNOWN;
109
110         return env_locations[prio];
111 }
112
113 /**
114  * env_get_location() - Returns the best env location for a board
115  * @op: operations performed on the environment
116  * @prio: priority between the multiple environments, 0 being the
117  *        highest priority
118  *
119  * This will return the preferred environment for the given priority.
120  * This is overridable by boards if they need to.
121  *
122  * All implementations are free to use the operation, the priority and
123  * any other data relevant to their choice, but must take into account
124  * the fact that the lowest prority (0) is the most important location
125  * in the system. The following locations should be returned by order
126  * of descending priorities, from the highest to the lowest priority.
127  *
128  * Returns:
129  * an enum env_location value on success, a negative error code otherwise
130  */
131 __weak enum env_location env_get_location(enum env_operation op, int prio)
132 {
133         return arch_env_get_location(op, prio);
134 }
135
136 /**
137  * env_driver_lookup() - Finds the most suited environment location
138  * @op: operations performed on the environment
139  * @prio: priority between the multiple environments, 0 being the
140  *        highest priority
141  *
142  * This will try to find the available environment with the highest
143  * priority in the system.
144  *
145  * Returns:
146  * NULL on error, a pointer to a struct env_driver otherwise
147  */
148 static struct env_driver *env_driver_lookup(enum env_operation op, int prio)
149 {
150         enum env_location loc = env_get_location(op, prio);
151         struct env_driver *drv;
152
153         if (loc == ENVL_UNKNOWN)
154                 return NULL;
155
156         drv = _env_driver_lookup(loc);
157         if (!drv) {
158                 debug("%s: No environment driver for location %d\n", __func__,
159                       loc);
160                 return NULL;
161         }
162
163         return drv;
164 }
165
166 int env_load(void)
167 {
168         struct env_driver *drv;
169         int best_prio = -1;
170         int prio;
171
172         if (CONFIG_IS_ENABLED(ENV_WRITEABLE_LIST)) {
173                 /*
174                  * When using a list of writeable variables, the baseline comes
175                  * from the built-in default env. So load this first.
176                  */
177                 env_set_default(NULL, 0);
178         }
179
180         for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) {
181                 int ret;
182
183                 if (!env_has_inited(drv->location))
184                         continue;
185
186                 printf("Loading Environment from %s... ", drv->name);
187                 /*
188                  * In error case, the error message must be printed during
189                  * drv->load() in some underlying API, and it must be exactly
190                  * one message.
191                  */
192                 ret = drv->load();
193                 if (!ret) {
194                         printf("OK\n");
195                         gd->env_load_prio = prio;
196
197                         return 0;
198                 } else if (ret == -ENOMSG) {
199                         /* Handle "bad CRC" case */
200                         if (best_prio == -1)
201                                 best_prio = prio;
202                 } else {
203                         debug("Failed (%d)\n", ret);
204                 }
205         }
206
207         /*
208          * In case of invalid environment, we set the 'default' env location
209          * to the best choice, i.e.:
210          *   1. Environment location with bad CRC, if such location was found
211          *   2. Otherwise use the location with highest priority
212          *
213          * This way, next calls to env_save() will restore the environment
214          * at the right place.
215          */
216         if (best_prio >= 0)
217                 debug("Selecting environment with bad CRC\n");
218         else
219                 best_prio = 0;
220
221         gd->env_load_prio = best_prio;
222
223         return -ENODEV;
224 }
225
226 int env_reload(void)
227 {
228         struct env_driver *drv;
229
230         drv = env_driver_lookup(ENVOP_LOAD, gd->env_load_prio);
231         if (drv) {
232                 int ret;
233
234                 printf("Loading Environment from %s... ", drv->name);
235
236                 if (!env_has_inited(drv->location)) {
237                         printf("not initialized\n");
238                         return -ENODEV;
239                 }
240
241                 ret = drv->load();
242                 if (ret)
243                         printf("Failed (%d)\n", ret);
244                 else
245                         printf("OK\n");
246
247                 if (!ret)
248                         return 0;
249         }
250
251         return -ENODEV;
252 }
253
254 int env_save(void)
255 {
256         struct env_driver *drv;
257
258         drv = env_driver_lookup(ENVOP_SAVE, gd->env_load_prio);
259         if (drv) {
260                 int ret;
261
262                 printf("Saving Environment to %s... ", drv->name);
263                 if (!drv->save) {
264                         printf("not possible\n");
265                         return -ENODEV;
266                 }
267
268                 if (!env_has_inited(drv->location)) {
269                         printf("not initialized\n");
270                         return -ENODEV;
271                 }
272
273                 ret = drv->save();
274                 if (ret)
275                         printf("Failed (%d)\n", ret);
276                 else
277                         printf("OK\n");
278
279                 if (!ret)
280                         return 0;
281         }
282
283         return -ENODEV;
284 }
285
286 int env_erase(void)
287 {
288         struct env_driver *drv;
289
290         drv = env_driver_lookup(ENVOP_ERASE, gd->env_load_prio);
291         if (drv) {
292                 int ret;
293
294                 if (!drv->erase) {
295                         printf("not possible\n");
296                         return -ENODEV;
297                 }
298
299                 if (!env_has_inited(drv->location)) {
300                         printf("not initialized\n");
301                         return -ENODEV;
302                 }
303
304                 printf("Erasing Environment on %s... ", drv->name);
305                 ret = drv->erase();
306                 if (ret)
307                         printf("Failed (%d)\n", ret);
308                 else
309                         printf("OK\n");
310
311                 if (!ret)
312                         return 0;
313         }
314
315         return -ENODEV;
316 }
317
318 int env_init(void)
319 {
320         struct env_driver *drv;
321         int ret = -ENOENT;
322         int prio;
323
324         for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
325                 if (!drv->init || !(ret = drv->init()))
326                         env_set_inited(drv->location);
327                 if (ret == -ENOENT)
328                         env_set_inited(drv->location);
329
330                 debug("%s: Environment %s init done (ret=%d)\n", __func__,
331                       drv->name, ret);
332
333                 if (gd->env_valid == ENV_INVALID)
334                         ret = -ENOENT;
335         }
336
337         if (!prio)
338                 return -ENODEV;
339
340         if (ret == -ENOENT) {
341                 gd->env_addr = (ulong)&default_environment[0];
342                 gd->env_valid = ENV_VALID;
343
344                 return 0;
345         }
346
347         return ret;
348 }
349
350 int env_select(const char *name)
351 {
352         struct env_driver *drv;
353         const int n_ents = ll_entry_count(struct env_driver, env_driver);
354         struct env_driver *entry;
355         int prio;
356         bool found = false;
357
358         printf("Select Environment on %s: ", name);
359
360         /* search ENV driver by name */
361         drv = ll_entry_start(struct env_driver, env_driver);
362         for (entry = drv; entry != drv + n_ents; entry++) {
363                 if (!strcmp(entry->name, name)) {
364                         found = true;
365                         break;
366                 }
367         }
368
369         if (!found) {
370                 printf("driver not found\n");
371                 return -ENODEV;
372         }
373
374         /* search priority by driver */
375         for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
376                 if (entry->location == env_get_location(ENVOP_LOAD, prio)) {
377                         /* when priority change, reset the ENV flags */
378                         if (gd->env_load_prio != prio) {
379                                 gd->env_load_prio = prio;
380                                 gd->env_valid = ENV_INVALID;
381                                 gd->flags &= ~GD_FLG_ENV_DEFAULT;
382                         }
383                         printf("OK\n");
384                         return 0;
385                 }
386         }
387         printf("priority not found\n");
388
389         return -ENODEV;
390 }
This page took 0.048508 seconds and 4 git commands to generate.