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