Blame view
common/env_flash.c
8.56 KB
c609719b8
|
1 |
/* |
ea882baf9
|
2 |
* (C) Copyright 2000-2010 |
c609719b8
|
3 4 5 6 |
* Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com> * Andreas Heppel <aheppel@sysgo.de> |
3765b3e7b
|
7 |
* SPDX-License-Identifier: GPL-2.0+ |
c609719b8
|
8 9 10 11 12 |
*/ /* #define DEBUG */ #include <common.h> |
c609719b8
|
13 14 |
#include <command.h> #include <environment.h> |
c609719b8
|
15 |
#include <linux/stddef.h> |
47cd00fa7
|
16 |
#include <malloc.h> |
ea882baf9
|
17 18 |
#include <search.h> #include <errno.h> |
c609719b8
|
19 |
|
d87080b72
|
20 |
DECLARE_GLOBAL_DATA_PTR; |
bdab39d35
|
21 |
#if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_FLASH) |
c609719b8
|
22 |
#define CMD_SAVEENV |
0e8d15866
|
23 |
#elif defined(CONFIG_ENV_ADDR_REDUND) |
82b54b972
|
24 |
#error CONFIG_ENV_ADDR_REDUND must have CONFIG_CMD_SAVEENV & CONFIG_CMD_FLASH |
c609719b8
|
25 |
#endif |
82b54b972
|
26 27 |
#if defined(CONFIG_ENV_SIZE_REDUND) && \ (CONFIG_ENV_SIZE_REDUND < CONFIG_ENV_SIZE) |
0e8d15866
|
28 |
#error CONFIG_ENV_SIZE_REDUND should not be less then CONFIG_ENV_SIZE |
c609719b8
|
29 |
#endif |
82b54b972
|
30 |
char *env_name_spec = "Flash"; |
c609719b8
|
31 32 |
#ifdef ENV_IS_EMBEDDED |
994bc671c
|
33 |
env_t *env_ptr = &environment; |
c609719b8
|
34 |
|
0e8d15866
|
35 |
static env_t *flash_addr = (env_t *)CONFIG_ENV_ADDR; |
c609719b8
|
36 37 |
#else /* ! ENV_IS_EMBEDDED */ |
0e8d15866
|
38 |
env_t *env_ptr = (env_t *)CONFIG_ENV_ADDR; |
0e8d15866
|
39 |
static env_t *flash_addr = (env_t *)CONFIG_ENV_ADDR; |
c609719b8
|
40 |
#endif /* ENV_IS_EMBEDDED */ |
ea882baf9
|
41 42 43 44 |
#if defined(CMD_SAVEENV) || defined(CONFIG_ENV_ADDR_REDUND) /* CONFIG_ENV_ADDR is supposed to be on sector boundary */ static ulong end_addr = CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1; #endif |
0e8d15866
|
45 46 |
#ifdef CONFIG_ENV_ADDR_REDUND static env_t *flash_addr_new = (env_t *)CONFIG_ENV_ADDR_REDUND; |
c609719b8
|
47 |
|
ea882baf9
|
48 |
/* CONFIG_ENV_ADDR_REDUND is supposed to be on sector boundary */ |
0e8d15866
|
49 |
static ulong end_addr_new = CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1; |
0e8d15866
|
50 |
#endif /* CONFIG_ENV_ADDR_REDUND */ |
c609719b8
|
51 |
|
c609719b8
|
52 |
|
0e8d15866
|
53 |
#ifdef CONFIG_ENV_ADDR_REDUND |
82b54b972
|
54 |
int env_init(void) |
c609719b8
|
55 |
{ |
8ed960461
|
56 |
int crc1_ok = 0, crc2_ok = 0; |
c609719b8
|
57 58 59 60 61 62 63 |
uchar flag1 = flash_addr->flags; uchar flag2 = flash_addr_new->flags; ulong addr_default = (ulong)&default_environment[0]; ulong addr1 = (ulong)&(flash_addr->data); ulong addr2 = (ulong)&(flash_addr_new->data); |
82b54b972
|
64 65 66 67 68 69 70 71 72 73 74 75 76 |
crc1_ok = crc32(0, flash_addr->data, ENV_SIZE) == flash_addr->crc; crc2_ok = crc32(0, flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc; if (crc1_ok && !crc2_ok) { gd->env_addr = addr1; gd->env_valid = 1; } else if (!crc1_ok && crc2_ok) { gd->env_addr = addr2; gd->env_valid = 1; } else if (!crc1_ok && !crc2_ok) { gd->env_addr = addr_default; gd->env_valid = 0; |
c3f9d4939
|
77 |
} else if (flag1 == ACTIVE_FLAG && flag2 == OBSOLETE_FLAG) { |
82b54b972
|
78 79 |
gd->env_addr = addr1; gd->env_valid = 1; |
c3f9d4939
|
80 |
} else if (flag1 == OBSOLETE_FLAG && flag2 == ACTIVE_FLAG) { |
82b54b972
|
81 82 |
gd->env_addr = addr2; gd->env_valid = 1; |
c3f9d4939
|
83 |
} else if (flag1 == flag2) { |
82b54b972
|
84 85 |
gd->env_addr = addr1; gd->env_valid = 2; |
c3f9d4939
|
86 |
} else if (flag1 == 0xFF) { |
82b54b972
|
87 88 |
gd->env_addr = addr1; gd->env_valid = 2; |
c3f9d4939
|
89 |
} else if (flag2 == 0xFF) { |
82b54b972
|
90 91 |
gd->env_addr = addr2; gd->env_valid = 2; |
c609719b8
|
92 |
} |
ea882baf9
|
93 |
return 0; |
c609719b8
|
94 95 96 97 98 |
} #ifdef CMD_SAVEENV int saveenv(void) { |
ea882baf9
|
99 100 |
env_t env_new; ssize_t len; |
82b54b972
|
101 |
char *res, *saved_data = NULL; |
ea882baf9
|
102 |
char flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG; |
82b54b972
|
103 |
int rc = 1; |
0e8d15866
|
104 |
#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE |
ea882baf9
|
105 |
ulong up_data = 0; |
500545cc6
|
106 |
#endif |
c609719b8
|
107 |
|
82b54b972
|
108 109 |
debug("Protect off %08lX ... %08lX ", (ulong)flash_addr, end_addr); |
c609719b8
|
110 |
|
82b54b972
|
111 |
if (flash_sect_protect(0, (ulong)flash_addr, end_addr)) |
ea882baf9
|
112 |
goto done; |
c609719b8
|
113 |
|
ea882baf9
|
114 115 |
debug("Protect off %08lX ... %08lX ", |
c609719b8
|
116 |
(ulong)flash_addr_new, end_addr_new); |
82b54b972
|
117 |
if (flash_sect_protect(0, (ulong)flash_addr_new, end_addr_new)) |
ea882baf9
|
118 |
goto done; |
ea882baf9
|
119 120 |
res = (char *)&env_new.data; |
be11235ab
|
121 |
len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); |
ea882baf9
|
122 123 124 125 |
if (len < 0) { error("Cannot export environment: errno = %d ", errno); goto done; |
c609719b8
|
126 |
} |
82b54b972
|
127 128 |
env_new.crc = crc32(0, env_new.data, ENV_SIZE); env_new.flags = new_flag; |
c609719b8
|
129 |
|
0e8d15866
|
130 |
#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE |
82b54b972
|
131 |
up_data = end_addr_new + 1 - ((long)flash_addr_new + CONFIG_ENV_SIZE); |
ea882baf9
|
132 133 |
debug("Data to save 0x%lX ", up_data); |
47cd00fa7
|
134 |
if (up_data) { |
82b54b972
|
135 136 |
saved_data = malloc(up_data); if (saved_data == NULL) { |
8bde7f776
|
137 138 |
printf("Unable to save the rest of sector (%ld) ", |
47cd00fa7
|
139 |
up_data); |
ea882baf9
|
140 |
goto done; |
47cd00fa7
|
141 |
} |
8bde7f776
|
142 |
memcpy(saved_data, |
82b54b972
|
143 144 |
(void *)((long)flash_addr_new + CONFIG_ENV_SIZE), up_data); |
ea882baf9
|
145 146 147 148 |
debug("Data (start 0x%lX, len 0x%lX) saved at 0x%p ", (long)flash_addr_new + CONFIG_ENV_SIZE, up_data, saved_data); |
47cd00fa7
|
149 150 |
} #endif |
ea882baf9
|
151 |
puts("Erasing Flash..."); |
82b54b972
|
152 |
debug(" %08lX ... %08lX ...", (ulong)flash_addr_new, end_addr_new); |
c609719b8
|
153 |
|
82b54b972
|
154 |
if (flash_sect_erase((ulong)flash_addr_new, end_addr_new)) |
ea882baf9
|
155 |
goto done; |
c609719b8
|
156 |
|
ea882baf9
|
157 158 |
puts("Writing to Flash... "); debug(" %08lX ... %08lX ...", |
c609719b8
|
159 |
(ulong)&(flash_addr_new->data), |
82b54b972
|
160 161 162 163 164 165 166 167 168 169 |
sizeof(env_ptr->data) + (ulong)&(flash_addr_new->data)); rc = flash_write((char *)&env_new, (ulong)flash_addr_new, sizeof(env_new)); if (rc) goto perror; rc = flash_write(&flag, (ulong)&(flash_addr->flags), sizeof(flash_addr->flags)); if (rc) goto perror; |
c609719b8
|
170 |
|
0e8d15866
|
171 |
#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE |
47cd00fa7
|
172 |
if (up_data) { /* restore the rest of sector */ |
ea882baf9
|
173 174 175 |
debug("Restoring the rest of data to 0x%lX len 0x%lX ", (long)flash_addr_new + CONFIG_ENV_SIZE, up_data); |
8bde7f776
|
176 |
if (flash_write(saved_data, |
0e8d15866
|
177 |
(long)flash_addr_new + CONFIG_ENV_SIZE, |
82b54b972
|
178 179 |
up_data)) goto perror; |
47cd00fa7
|
180 181 |
} #endif |
ea882baf9
|
182 183 |
puts("done "); |
c609719b8
|
184 |
{ |
82b54b972
|
185 |
env_t *etmp = flash_addr; |
c609719b8
|
186 187 188 189 190 191 192 193 194 195 |
ulong ltmp = end_addr; flash_addr = flash_addr_new; flash_addr_new = etmp; end_addr = end_addr_new; end_addr_new = ltmp; } rc = 0; |
82b54b972
|
196 197 198 |
goto done; perror: flash_perror(rc); |
ea882baf9
|
199 |
done: |
47cd00fa7
|
200 |
if (saved_data) |
ea882baf9
|
201 |
free(saved_data); |
c609719b8
|
202 |
/* try to re-protect */ |
82b54b972
|
203 204 |
flash_sect_protect(1, (ulong)flash_addr, end_addr); flash_sect_protect(1, (ulong)flash_addr_new, end_addr_new); |
c609719b8
|
205 206 207 208 |
return rc; } #endif /* CMD_SAVEENV */ |
0e8d15866
|
209 |
#else /* ! CONFIG_ENV_ADDR_REDUND */ |
c609719b8
|
210 |
|
82b54b972
|
211 |
int env_init(void) |
c609719b8
|
212 |
{ |
c609719b8
|
213 |
if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { |
82b54b972
|
214 215 216 |
gd->env_addr = (ulong)&(env_ptr->data); gd->env_valid = 1; return 0; |
c609719b8
|
217 |
} |
9bb8b209e
|
218 |
|
82b54b972
|
219 220 |
gd->env_addr = (ulong)&default_environment[0]; gd->env_valid = 0; |
ea882baf9
|
221 |
return 0; |
c609719b8
|
222 223 224 |
} #ifdef CMD_SAVEENV |
c609719b8
|
225 226 |
int saveenv(void) { |
ea882baf9
|
227 228 229 |
env_t env_new; ssize_t len; int rc = 1; |
82b54b972
|
230 |
char *res, *saved_data = NULL; |
ea882baf9
|
231 232 |
#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE ulong up_data = 0; |
c609719b8
|
233 |
|
82b54b972
|
234 |
up_data = end_addr + 1 - ((long)flash_addr + CONFIG_ENV_SIZE); |
ea882baf9
|
235 236 237 |
debug("Data to save 0x%lx ", up_data); if (up_data) { |
82b54b972
|
238 239 |
saved_data = malloc(up_data); if (saved_data == NULL) { |
ea882baf9
|
240 241 242 243 244 245 246 247 248 249 250 251 252 |
printf("Unable to save the rest of sector (%ld) ", up_data); goto done; } memcpy(saved_data, (void *)((long)flash_addr + CONFIG_ENV_SIZE), up_data); debug("Data (start 0x%lx, len 0x%lx) saved at 0x%lx ", (ulong)flash_addr + CONFIG_ENV_SIZE, up_data, (ulong)saved_data); } |
0e8d15866
|
253 |
#endif /* CONFIG_ENV_SECT_SIZE */ |
c609719b8
|
254 |
|
82b54b972
|
255 256 |
debug("Protect off %08lX ... %08lX ", (ulong)flash_addr, end_addr); |
c609719b8
|
257 |
|
ea882baf9
|
258 259 |
if (flash_sect_protect(0, (long)flash_addr, end_addr)) goto done; |
c609719b8
|
260 |
|
ea882baf9
|
261 |
res = (char *)&env_new.data; |
be11235ab
|
262 |
len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); |
ea882baf9
|
263 264 265 266 267 268 |
if (len < 0) { error("Cannot export environment: errno = %d ", errno); goto done; } env_new.crc = crc32(0, env_new.data, ENV_SIZE); |
c609719b8
|
269 |
|
ea882baf9
|
270 271 272 |
puts("Erasing Flash..."); if (flash_sect_erase((long)flash_addr, end_addr)) goto done; |
c609719b8
|
273 |
|
ea882baf9
|
274 275 |
puts("Writing to Flash... "); rc = flash_write((char *)&env_new, (long)flash_addr, CONFIG_ENV_SIZE); |
82b54b972
|
276 277 |
if (rc != 0) goto perror; |
ea882baf9
|
278 279 280 281 282 283 284 |
#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE if (up_data) { /* restore the rest of sector */ debug("Restoring the rest of data to 0x%lx len 0x%lx ", (ulong)flash_addr + CONFIG_ENV_SIZE, up_data); if (flash_write(saved_data, (long)flash_addr + CONFIG_ENV_SIZE, |
82b54b972
|
285 286 |
up_data)) goto perror; |
ea882baf9
|
287 288 289 290 291 |
} #endif puts("done "); rc = 0; |
82b54b972
|
292 293 294 |
goto done; perror: flash_perror(rc); |
ea882baf9
|
295 296 297 |
done: if (saved_data) free(saved_data); |
c609719b8
|
298 |
/* try to re-protect */ |
82b54b972
|
299 |
flash_sect_protect(1, (long)flash_addr, end_addr); |
ea882baf9
|
300 |
return rc; |
c609719b8
|
301 |
} |
c609719b8
|
302 |
#endif /* CMD_SAVEENV */ |
0e8d15866
|
303 |
#endif /* CONFIG_ENV_ADDR_REDUND */ |
c609719b8
|
304 |
|
ea882baf9
|
305 |
void env_relocate_spec(void) |
c609719b8
|
306 |
{ |
0e8d15866
|
307 |
#ifdef CONFIG_ENV_ADDR_REDUND |
c3f9d4939
|
308 |
if (gd->env_addr != (ulong)&(flash_addr->data)) { |
ea882baf9
|
309 |
env_t *etmp = flash_addr; |
c609719b8
|
310 311 312 313 314 315 316 317 |
ulong ltmp = end_addr; flash_addr = flash_addr_new; flash_addr_new = etmp; end_addr = end_addr_new; end_addr_new = ltmp; } |
c3f9d4939
|
318 |
if (flash_addr_new->flags != OBSOLETE_FLAG && |
82b54b972
|
319 |
crc32(0, flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc) { |
c3f9d4939
|
320 |
char flag = OBSOLETE_FLAG; |
c609719b8
|
321 |
gd->env_valid = 2; |
ea882baf9
|
322 |
flash_sect_protect(0, (ulong)flash_addr_new, end_addr_new); |
c3f9d4939
|
323 |
flash_write(&flag, |
8bde7f776
|
324 325 |
(ulong)&(flash_addr_new->flags), sizeof(flash_addr_new->flags)); |
ea882baf9
|
326 |
flash_sect_protect(1, (ulong)flash_addr_new, end_addr_new); |
c609719b8
|
327 |
} |
c3f9d4939
|
328 329 330 |
if (flash_addr->flags != ACTIVE_FLAG && (flash_addr->flags & ACTIVE_FLAG) == ACTIVE_FLAG) { char flag = ACTIVE_FLAG; |
c609719b8
|
331 |
gd->env_valid = 2; |
ea882baf9
|
332 |
flash_sect_protect(0, (ulong)flash_addr, end_addr); |
c3f9d4939
|
333 |
flash_write(&flag, |
8bde7f776
|
334 335 |
(ulong)&(flash_addr->flags), sizeof(flash_addr->flags)); |
ea882baf9
|
336 |
flash_sect_protect(1, (ulong)flash_addr, end_addr); |
c609719b8
|
337 338 339 |
} if (gd->env_valid == 2) |
82b54b972
|
340 341 342 343 |
puts("*** Warning - some problems detected " "reading environment; recovered successfully "); |
0e8d15866
|
344 |
#endif /* CONFIG_ENV_ADDR_REDUND */ |
ea882baf9
|
345 346 |
env_import((char *)flash_addr, 1); |
c609719b8
|
347 |
} |