Blame view

env/env.c 6.22 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
c9d728dd3   Simon Glass   env: Add a new im...
2
3
4
  /*
   * Copyright (C) 2017 Google, Inc
   * Written by Simon Glass <sjg@chromium.org>
c9d728dd3   Simon Glass   env: Add a new im...
5
6
7
8
9
10
   */
  
  #include <common.h>
  #include <environment.h>
  
  DECLARE_GLOBAL_DATA_PTR;
7bcdf1957   Siva Durga Prasad Paladugu   env: Relocate env...
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  #if defined(CONFIG_NEEDS_MANUAL_RELOC)
  void env_fix_drivers(void)
  {
  	struct env_driver *drv;
  	const int n_ents = ll_entry_count(struct env_driver, env_driver);
  	struct env_driver *entry;
  
  	drv = ll_entry_start(struct env_driver, env_driver);
  	for (entry = drv; entry != drv + n_ents; entry++) {
  		if (entry->name)
  			entry->name += gd->reloc_off;
  		if (entry->load)
  			entry->load += gd->reloc_off;
  		if (entry->save)
  			entry->save += gd->reloc_off;
  		if (entry->init)
  			entry->init += gd->reloc_off;
  	}
  }
  #endif
52746c43d   Maxime Ripard   env: Rename env_d...
31
  static struct env_driver *_env_driver_lookup(enum env_location loc)
c9d728dd3   Simon Glass   env: Add a new im...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  {
  	struct env_driver *drv;
  	const int n_ents = ll_entry_count(struct env_driver, env_driver);
  	struct env_driver *entry;
  
  	drv = ll_entry_start(struct env_driver, env_driver);
  	for (entry = drv; entry != drv + n_ents; entry++) {
  		if (loc == entry->location)
  			return entry;
  	}
  
  	/* Not found */
  	return NULL;
  }
7d714a24d   Maxime Ripard   env: Support mult...
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  static enum env_location env_locations[] = {
  #ifdef CONFIG_ENV_IS_IN_EEPROM
  	ENVL_EEPROM,
  #endif
  #ifdef CONFIG_ENV_IS_IN_EXT4
  	ENVL_EXT4,
  #endif
  #ifdef CONFIG_ENV_IS_IN_FAT
  	ENVL_FAT,
  #endif
  #ifdef CONFIG_ENV_IS_IN_FLASH
  	ENVL_FLASH,
  #endif
  #ifdef CONFIG_ENV_IS_IN_MMC
  	ENVL_MMC,
  #endif
  #ifdef CONFIG_ENV_IS_IN_NAND
  	ENVL_NAND,
  #endif
  #ifdef CONFIG_ENV_IS_IN_NVRAM
  	ENVL_NVRAM,
  #endif
  #ifdef CONFIG_ENV_IS_IN_REMOTE
  	ENVL_REMOTE,
  #endif
9a6a311d2   Ye Li   env: sata: Add mi...
71
72
73
  #ifdef CONFIG_ENV_IS_IN_SATA
  	ENVL_ESATA,
  #endif
7d714a24d   Maxime Ripard   env: Support mult...
74
75
76
77
78
79
  #ifdef CONFIG_ENV_IS_IN_SPI_FLASH
  	ENVL_SPI_FLASH,
  #endif
  #ifdef CONFIG_ENV_IS_IN_UBI
  	ENVL_UBI,
  #endif
606469c94   Ye Li   MLK-22279-2 env: ...
80
  #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_ENV_DEFAULT_NOWHERE)
7d714a24d   Maxime Ripard   env: Support mult...
81
82
83
  	ENVL_NOWHERE,
  #endif
  };
1d4460871   Maxime Ripard   env: Initialise a...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  static bool env_has_inited(enum env_location location)
  {
  	return gd->env_has_init & BIT(location);
  }
  
  static void env_set_inited(enum env_location location)
  {
  	/*
  	 * We're using a 32-bits bitmask stored in gd (env_has_init)
  	 * using the above enum value as the bit index. We need to
  	 * make sure that we're not overflowing it.
  	 */
  	BUILD_BUG_ON(ARRAY_SIZE(env_locations) > BITS_PER_LONG);
  
  	gd->env_has_init |= BIT(location);
  }
8a3a7e227   Maxime Ripard   env: Pass additio...
100
101
102
103
104
105
106
  /**
   * env_get_location() - Returns the best env location for a board
   * @op: operations performed on the environment
   * @prio: priority between the multiple environments, 0 being the
   *        highest priority
   *
   * This will return the preferred environment for the given priority.
40c08a68b   Maxime Ripard   env: Mark env_get...
107
   * This is overridable by boards if they need to.
8a3a7e227   Maxime Ripard   env: Pass additio...
108
109
110
111
112
113
114
115
116
117
   *
   * All implementations are free to use the operation, the priority and
   * any other data relevant to their choice, but must take into account
   * the fact that the lowest prority (0) is the most important location
   * in the system. The following locations should be returned by order
   * of descending priorities, from the highest to the lowest priority.
   *
   * Returns:
   * an enum env_location value on success, a negative error code otherwise
   */
40c08a68b   Maxime Ripard   env: Mark env_get...
118
  __weak enum env_location env_get_location(enum env_operation op, int prio)
c9d728dd3   Simon Glass   env: Add a new im...
119
  {
d30ba2315   Nicholas Faustini   u-boot: remove dr...
120
121
122
123
  	if (prio >= ARRAY_SIZE(env_locations))
  		return ENVL_UNKNOWN;
  
  	gd->env_load_prio = prio;
8a3a7e227   Maxime Ripard   env: Pass additio...
124

d30ba2315   Nicholas Faustini   u-boot: remove dr...
125
  	return env_locations[prio];
c9d728dd3   Simon Glass   env: Add a new im...
126
  }
8a3a7e227   Maxime Ripard   env: Pass additio...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  
  /**
   * env_driver_lookup() - Finds the most suited environment location
   * @op: operations performed on the environment
   * @prio: priority between the multiple environments, 0 being the
   *        highest priority
   *
   * This will try to find the available environment with the highest
   * priority in the system.
   *
   * Returns:
   * NULL on error, a pointer to a struct env_driver otherwise
   */
  static struct env_driver *env_driver_lookup(enum env_operation op, int prio)
c9d728dd3   Simon Glass   env: Add a new im...
141
  {
8a3a7e227   Maxime Ripard   env: Pass additio...
142
  	enum env_location loc = env_get_location(op, prio);
c9d728dd3   Simon Glass   env: Add a new im...
143
  	struct env_driver *drv;
8a3a7e227   Maxime Ripard   env: Pass additio...
144
145
  	if (loc == ENVL_UNKNOWN)
  		return NULL;
52746c43d   Maxime Ripard   env: Rename env_d...
146
  	drv = _env_driver_lookup(loc);
c9d728dd3   Simon Glass   env: Add a new im...
147
148
149
150
151
152
153
154
155
  	if (!drv) {
  		debug("%s: No environment driver for location %d
  ", __func__,
  		      loc);
  		return NULL;
  	}
  
  	return drv;
  }
b2cdef486   Goldschmidt Simon   env: restore old ...
156
  __weak int env_get_char_spec(int index)
c9d728dd3   Simon Glass   env: Add a new im...
157
  {
b2cdef486   Goldschmidt Simon   env: restore old ...
158
159
  	return *(uchar *)(gd->env_addr + index);
  }
c9d728dd3   Simon Glass   env: Add a new im...
160

b2cdef486   Goldschmidt Simon   env: restore old ...
161
162
  int env_get_char(int index)
  {
2d7cb5b42   Simon Glass   env: Replace all ...
163
  	if (gd->env_valid == ENV_INVALID)
a69d0f60e   Simon Glass   env: Drop env_get...
164
  		return default_environment[index];
b2cdef486   Goldschmidt Simon   env: restore old ...
165
166
  	else
  		return env_get_char_spec(index);
c9d728dd3   Simon Glass   env: Add a new im...
167
168
169
170
  }
  
  int env_load(void)
  {
8a3a7e227   Maxime Ripard   env: Pass additio...
171
  	struct env_driver *drv;
293a172b6   Sam Protsenko   env: Fix saving e...
172
  	int best_prio = -1;
8a3a7e227   Maxime Ripard   env: Pass additio...
173
  	int prio;
c9d728dd3   Simon Glass   env: Add a new im...
174

8a3a7e227   Maxime Ripard   env: Pass additio...
175
176
177
178
179
  	for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) {
  		int ret;
  
  		if (!drv->load)
  			continue;
1d4460871   Maxime Ripard   env: Initialise a...
180
181
  		if (!env_has_inited(drv->location))
  			continue;
3574ba019   Maxime Ripard   env: Make it expl...
182
  		printf("Loading Environment from %s... ", drv->name);
13bbfb4a3   Sam Protsenko   env: Don't show "...
183
184
185
186
187
  		/*
  		 * In error case, the error message must be printed during
  		 * drv->load() in some underlying API, and it must be exactly
  		 * one message.
  		 */
8a3a7e227   Maxime Ripard   env: Pass additio...
188
  		ret = drv->load();
293a172b6   Sam Protsenko   env: Fix saving e...
189
  		if (!ret) {
3574ba019   Maxime Ripard   env: Make it expl...
190
191
  			printf("OK
  ");
8a3a7e227   Maxime Ripard   env: Pass additio...
192
  			return 0;
293a172b6   Sam Protsenko   env: Fix saving e...
193
194
195
196
197
198
199
  		} else if (ret == -ENOMSG) {
  			/* Handle "bad CRC" case */
  			if (best_prio == -1)
  				best_prio = prio;
  		} else {
  			debug("Failed (%d)
  ", ret);
13bbfb4a3   Sam Protsenko   env: Don't show "...
200
  		}
c9d728dd3   Simon Glass   env: Add a new im...
201
  	}
d30ba2315   Nicholas Faustini   u-boot: remove dr...
202
203
  	/*
  	 * In case of invalid environment, we set the 'default' env location
293a172b6   Sam Protsenko   env: Fix saving e...
204
205
206
207
208
209
  	 * to the best choice, i.e.:
  	 *   1. Environment location with bad CRC, if such location was found
  	 *   2. Otherwise use the location with highest priority
  	 *
  	 * This way, next calls to env_save() will restore the environment
  	 * at the right place.
d30ba2315   Nicholas Faustini   u-boot: remove dr...
210
  	 */
293a172b6   Sam Protsenko   env: Fix saving e...
211
212
213
214
215
216
  	if (best_prio >= 0)
  		debug("Selecting environment with bad CRC
  ");
  	else
  		best_prio = 0;
  	env_get_location(ENVOP_LOAD, best_prio);
d30ba2315   Nicholas Faustini   u-boot: remove dr...
217

8a3a7e227   Maxime Ripard   env: Pass additio...
218
  	return -ENODEV;
c9d728dd3   Simon Glass   env: Add a new im...
219
220
221
222
  }
  
  int env_save(void)
  {
8a3a7e227   Maxime Ripard   env: Pass additio...
223
  	struct env_driver *drv;
c9d728dd3   Simon Glass   env: Add a new im...
224

d30ba2315   Nicholas Faustini   u-boot: remove dr...
225
226
  	drv = env_driver_lookup(ENVOP_SAVE, gd->env_load_prio);
  	if (drv) {
8a3a7e227   Maxime Ripard   env: Pass additio...
227
228
229
  		int ret;
  
  		if (!drv->save)
d30ba2315   Nicholas Faustini   u-boot: remove dr...
230
  			return -ENODEV;
8a3a7e227   Maxime Ripard   env: Pass additio...
231

1d4460871   Maxime Ripard   env: Initialise a...
232
  		if (!env_has_inited(drv->location))
d30ba2315   Nicholas Faustini   u-boot: remove dr...
233
  			return -ENODEV;
1d4460871   Maxime Ripard   env: Initialise a...
234

9efac3c80   Maxime Ripard   env: Make the env...
235
  		printf("Saving Environment to %s... ", drv->name);
8a3a7e227   Maxime Ripard   env: Pass additio...
236
  		ret = drv->save();
3574ba019   Maxime Ripard   env: Make it expl...
237
238
239
240
241
242
  		if (ret)
  			printf("Failed (%d)
  ", ret);
  		else
  			printf("OK
  ");
8a3a7e227   Maxime Ripard   env: Pass additio...
243
244
  		if (!ret)
  			return 0;
c9d728dd3   Simon Glass   env: Add a new im...
245
  	}
8a3a7e227   Maxime Ripard   env: Pass additio...
246
  	return -ENODEV;
c9d728dd3   Simon Glass   env: Add a new im...
247
  }
6eeae4246   Simon Glass   env: Drop env_ini...
248
  int env_init(void)
c9d728dd3   Simon Glass   env: Add a new im...
249
  {
8a3a7e227   Maxime Ripard   env: Pass additio...
250
  	struct env_driver *drv;
7938822a6   Simon Glass   env: Drop common ...
251
  	int ret = -ENOENT;
8a3a7e227   Maxime Ripard   env: Pass additio...
252
253
254
  	int prio;
  
  	for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
1d4460871   Maxime Ripard   env: Initialise a...
255
256
  		if (!drv->init || !(ret = drv->init()))
  			env_set_inited(drv->location);
8a3a7e227   Maxime Ripard   env: Pass additio...
257

1d4460871   Maxime Ripard   env: Initialise a...
258
259
  		debug("%s: Environment %s init done (ret=%d)
  ", __func__,
8a3a7e227   Maxime Ripard   env: Pass additio...
260
261
262
263
264
  		      drv->name, ret);
  	}
  
  	if (!prio)
  		return -ENODEV;
7938822a6   Simon Glass   env: Drop common ...
265
266
  	if (ret == -ENOENT) {
  		gd->env_addr = (ulong)&default_environment[0];
eeba55cb4   Tom Rini   env: Correct case...
267
  		gd->env_valid = ENV_VALID;
7938822a6   Simon Glass   env: Drop common ...
268
269
  
  		return 0;
c9d728dd3   Simon Glass   env: Add a new im...
270
  	}
8a3a7e227   Maxime Ripard   env: Pass additio...
271
  	return ret;
c9d728dd3   Simon Glass   env: Add a new im...
272
  }
565d9002a   Ye Li   MLK-22279-1 env: ...
273
274
275
276
277
278
279
  
  #ifndef ENV_IS_EMBEDDED
  __weak long long env_get_offset(long long defautl_offset)
  {
  	return defautl_offset;
  }
  #endif