]> git.sur5r.net Git - u-boot/blob - env/env.c
90d65974d0c9e05c5d4133ca3f6b08f44f20cbdd
[u-boot] / env / env.c
1 /*
2  * Copyright (C) 2017 Google, Inc
3  * Written by Simon Glass <sjg@chromium.org>
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <environment.h>
10
11 DECLARE_GLOBAL_DATA_PTR;
12
13 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
14 void env_fix_drivers(void)
15 {
16         struct env_driver *drv;
17         const int n_ents = ll_entry_count(struct env_driver, env_driver);
18         struct env_driver *entry;
19
20         drv = ll_entry_start(struct env_driver, env_driver);
21         for (entry = drv; entry != drv + n_ents; entry++) {
22                 if (entry->name)
23                         entry->name += gd->reloc_off;
24                 if (entry->load)
25                         entry->load += gd->reloc_off;
26                 if (entry->save)
27                         entry->save += gd->reloc_off;
28                 if (entry->init)
29                         entry->init += gd->reloc_off;
30         }
31 }
32 #endif
33
34 static struct env_driver *_env_driver_lookup(enum env_location loc)
35 {
36         struct env_driver *drv;
37         const int n_ents = ll_entry_count(struct env_driver, env_driver);
38         struct env_driver *entry;
39
40         drv = ll_entry_start(struct env_driver, env_driver);
41         for (entry = drv; entry != drv + n_ents; entry++) {
42                 if (loc == entry->location)
43                         return entry;
44         }
45
46         /* Not found */
47         return NULL;
48 }
49
50 static enum env_location env_locations[] = {
51 #ifdef CONFIG_ENV_IS_IN_EEPROM
52         ENVL_EEPROM,
53 #endif
54 #ifdef CONFIG_ENV_IS_IN_EXT4
55         ENVL_EXT4,
56 #endif
57 #ifdef CONFIG_ENV_IS_IN_FAT
58         ENVL_FAT,
59 #endif
60 #ifdef CONFIG_ENV_IS_IN_FLASH
61         ENVL_FLASH,
62 #endif
63 #ifdef CONFIG_ENV_IS_IN_MMC
64         ENVL_MMC,
65 #endif
66 #ifdef CONFIG_ENV_IS_IN_NAND
67         ENVL_NAND,
68 #endif
69 #ifdef CONFIG_ENV_IS_IN_NVRAM
70         ENVL_NVRAM,
71 #endif
72 #ifdef CONFIG_ENV_IS_IN_REMOTE
73         ENVL_REMOTE,
74 #endif
75 #ifdef CONFIG_ENV_IS_IN_SPI_FLASH
76         ENVL_SPI_FLASH,
77 #endif
78 #ifdef CONFIG_ENV_IS_IN_UBI
79         ENVL_UBI,
80 #endif
81 #ifdef CONFIG_ENV_IS_NOWHERE
82         ENVL_NOWHERE,
83 #endif
84 };
85
86 static bool env_has_inited(enum env_location location)
87 {
88         return gd->env_has_init & BIT(location);
89 }
90
91 static void env_set_inited(enum env_location location)
92 {
93         /*
94          * We're using a 32-bits bitmask stored in gd (env_has_init)
95          * using the above enum value as the bit index. We need to
96          * make sure that we're not overflowing it.
97          */
98         BUILD_BUG_ON(ARRAY_SIZE(env_locations) > BITS_PER_LONG);
99
100         gd->env_has_init |= BIT(location);
101 }
102
103 /**
104  * env_get_location() - Returns the best env location for a board
105  * @op: operations performed on the environment
106  * @prio: priority between the multiple environments, 0 being the
107  *        highest priority
108  *
109  * This will return the preferred environment for the given priority.
110  * This is overridable by boards if they need to.
111  *
112  * All implementations are free to use the operation, the priority and
113  * any other data relevant to their choice, but must take into account
114  * the fact that the lowest prority (0) is the most important location
115  * in the system. The following locations should be returned by order
116  * of descending priorities, from the highest to the lowest priority.
117  *
118  * Returns:
119  * an enum env_location value on success, a negative error code otherwise
120  */
121 __weak enum env_location env_get_location(enum env_operation op, int prio)
122 {
123         switch (op) {
124         case ENVOP_GET_CHAR:
125         case ENVOP_INIT:
126         case ENVOP_LOAD:
127                 if (prio >= ARRAY_SIZE(env_locations))
128                         return ENVL_UNKNOWN;
129
130                 gd->env_load_location = env_locations[prio];
131                 return gd->env_load_location;
132
133         case ENVOP_SAVE:
134                 return gd->env_load_location;
135         }
136
137         return ENVL_UNKNOWN;
138 }
139
140
141 /**
142  * env_driver_lookup() - Finds the most suited environment location
143  * @op: operations performed on the environment
144  * @prio: priority between the multiple environments, 0 being the
145  *        highest priority
146  *
147  * This will try to find the available environment with the highest
148  * priority in the system.
149  *
150  * Returns:
151  * NULL on error, a pointer to a struct env_driver otherwise
152  */
153 static struct env_driver *env_driver_lookup(enum env_operation op, int prio)
154 {
155         enum env_location loc = env_get_location(op, prio);
156         struct env_driver *drv;
157
158         if (loc == ENVL_UNKNOWN)
159                 return NULL;
160
161         drv = _env_driver_lookup(loc);
162         if (!drv) {
163                 debug("%s: No environment driver for location %d\n", __func__,
164                       loc);
165                 return NULL;
166         }
167
168         return drv;
169 }
170
171 __weak int env_get_char_spec(int index)
172 {
173         return *(uchar *)(gd->env_addr + index);
174 }
175
176 int env_get_char(int index)
177 {
178         if (gd->env_valid == ENV_INVALID)
179                 return default_environment[index];
180         else
181                 return env_get_char_spec(index);
182 }
183
184 int env_load(void)
185 {
186         struct env_driver *drv;
187         int prio;
188
189         for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) {
190                 int ret;
191
192                 if (!drv->load)
193                         continue;
194
195                 if (!env_has_inited(drv->location))
196                         continue;
197
198                 printf("Loading Environment from %s... ", drv->name);
199                 ret = drv->load();
200                 if (ret)
201                         printf("Failed (%d)\n", ret);
202                 else
203                         printf("OK\n");
204
205                 if (!ret)
206                         return 0;
207         }
208
209         return -ENODEV;
210 }
211
212 int env_save(void)
213 {
214         struct env_driver *drv;
215         int prio;
216
217         for (prio = 0; (drv = env_driver_lookup(ENVOP_SAVE, prio)); prio++) {
218                 int ret;
219
220                 if (!drv->save)
221                         continue;
222
223                 if (!env_has_inited(drv->location))
224                         continue;
225
226                 printf("Saving Environment to %s... ", drv->name);
227                 ret = drv->save();
228                 if (ret)
229                         printf("Failed (%d)\n", ret);
230                 else
231                         printf("OK\n");
232
233                 if (!ret)
234                         return 0;
235         }
236
237         return -ENODEV;
238 }
239
240 int env_init(void)
241 {
242         struct env_driver *drv;
243         int ret = -ENOENT;
244         int prio;
245
246         for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
247                 if (!drv->init || !(ret = drv->init()))
248                         env_set_inited(drv->location);
249
250                 debug("%s: Environment %s init done (ret=%d)\n", __func__,
251                       drv->name, ret);
252         }
253
254         if (!prio)
255                 return -ENODEV;
256
257         if (ret == -ENOENT) {
258                 gd->env_addr = (ulong)&default_environment[0];
259                 gd->env_valid = ENV_VALID;
260
261                 return 0;
262         }
263
264         return ret;
265 }