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