1/* 2 * NVRAM variable manipulation (direct mapped flash) 3 * 4 * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: nvram_rw.c 258972 2011-05-11 08:57:26Z $ 19 */ 20 21#include <bcm_cfg.h> 22#include <typedefs.h> 23#include <bcmdefs.h> 24#include <osl.h> 25#include <bcmutils.h> 26#include <siutils.h> 27#include <bcmnvram.h> 28#include <bcmendian.h> 29#include <flashutl.h> 30#include <hndsoc.h> 31#include <sbchipc.h> 32#include <LzmaDec.h> 33#ifdef NFLASH_SUPPORT 34#include <hndnand.h> 35#endif /* NFLASH_SUPPORT */ 36#ifdef _CFE_ 37#include <hndsflash.h> 38#else 39 40#endif 41 42struct nvram_tuple *_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value); 43void _nvram_free(struct nvram_tuple *t); 44int _nvram_read(void *buf, int idx); 45 46extern char *_nvram_get(const char *name); 47extern int _nvram_set(const char *name, const char *value); 48extern int _nvram_unset(const char *name); 49extern int _nvram_getall(char *buf, int count); 50extern int _nvram_commit(struct nvram_header *header); 51extern int _nvram_init(void *si, int idx); 52extern void _nvram_exit(void); 53 54static struct nvram_header *nvram_header = NULL; 55static int nvram_do_reset = FALSE; 56 57#if defined(_CFE_) && defined(BCM_DEVINFO) 58int _nvram_hash_sync(void); 59 60char *devinfo_flashdrv_nvram = "flash0.devinfo"; 61 62static struct nvram_header *devinfo_nvram_header = NULL; 63static unsigned char devinfo_nvram_nvh[MAX_NVRAM_SPACE]; 64#endif /* _CFE_ && BCM_DEVINFO */ 65 66#ifdef _CFE_ 67/* For NAND boot, flash0.nvram will be changed to nflash0.nvram */ 68char *flashdrv_nvram = "flash0.nvram"; 69#endif 70 71#if defined(__ECOS) 72extern int kernel_initial; 73#define NVRAM_LOCK() cyg_scheduler_lock() 74#define NVRAM_UNLOCK() cyg_scheduler_unlock() 75#else 76#define NVRAM_LOCK() do {} while (0) 77#define NVRAM_UNLOCK() do {} while (0) 78#endif 79 80/* Convenience */ 81#define KB * 1024 82#define MB * 1024 * 1024 83 84char * 85nvram_get(const char *name) 86{ 87 char *value; 88 89#ifdef __ECOS 90 if (!kernel_initial) 91 return NULL; 92#endif 93 94 NVRAM_LOCK(); 95 value = _nvram_get(name); 96 NVRAM_UNLOCK(); 97 98 return value; 99} 100 101int 102nvram_getall(char *buf, int count) 103{ 104 int ret; 105 106 NVRAM_LOCK(); 107 ret = _nvram_getall(buf, count); 108 NVRAM_UNLOCK(); 109 110 return ret; 111} 112 113int 114BCMINITFN(nvram_set)(const char *name, const char *value) 115{ 116 int ret; 117 118 NVRAM_LOCK(); 119 ret = _nvram_set(name, value); 120 NVRAM_UNLOCK(); 121 122 return ret; 123} 124 125int 126BCMINITFN(nvram_unset)(const char *name) 127{ 128 int ret; 129 130 NVRAM_LOCK(); 131 ret = _nvram_unset(name); 132 NVRAM_UNLOCK(); 133 134 return ret; 135} 136 137int 138BCMINITFN(nvram_resetgpio_init)(void *si) 139{ 140 char *value; 141 int gpio; 142 si_t *sih; 143 144 sih = (si_t *)si; 145 146 value = nvram_get("reset_gpio"); 147 if (!value) 148 return -1; 149 150 gpio = (int) bcm_atoi(value); 151 if (gpio > 31) 152 return -1; 153 154 /* Setup GPIO input */ 155 si_gpioouten(sih, ((uint32) 1 << gpio), 0, GPIO_DRV_PRIORITY); 156 157 return gpio; 158} 159 160int 161BCMINITFN(nvram_reset)(void *si) 162{ 163 int gpio; 164 uint msec; 165 si_t * sih = (si_t *)si; 166 167 if ((gpio = nvram_resetgpio_init((void *)sih)) < 0) 168 return FALSE; 169 170 /* GPIO reset is asserted low */ 171 for (msec = 0; msec < 5000; msec++) { 172 if (si_gpioin(sih) & ((uint32) 1 << gpio)) 173 return FALSE; 174 OSL_DELAY(1000); 175 } 176 177 nvram_do_reset = TRUE; 178 return TRUE; 179} 180 181#ifdef NFLASH_SUPPORT 182static unsigned char nand_nvh[MAX_NVRAM_SPACE]; 183 184static struct nvram_header * 185BCMINITFN(nand_find_nvram)(hndnand_t *nfl, uint32 off) 186{ 187 int blocksize = nfl->blocksize; 188 unsigned char *buf = nand_nvh; 189 int rlen = sizeof(nand_nvh); 190 int len; 191 192 for (; off < nfl_boot_size(nfl); off += blocksize) { 193 if (hndnand_checkbadb(nfl, off) != 0) 194 continue; 195 196 len = blocksize; 197 if (len >= rlen) 198 len = rlen; 199 200 if (hndnand_read(nfl, off, len, buf) == 0) 201 break; 202 203 buf += len; 204 rlen -= len; 205 if (rlen == 0) 206 return (struct nvram_header *)nand_nvh; 207 } 208 209 return NULL; 210} 211#endif /* NFLASH_SUPPORT */ 212 213extern unsigned char embedded_nvram[]; 214 215static struct nvram_header * 216BCMINITFN(find_nvram)(si_t *sih, bool embonly, bool *isemb) 217{ 218 struct nvram_header *nvh; 219 uint32 off, lim = SI_FLASH2_SZ; 220 uint32 flbase = SI_FLASH2; 221 int bootdev; 222#ifdef NFLASH_SUPPORT 223 hndnand_t *nfl_info = NULL; 224#endif 225#ifdef _CFE_ 226 hndsflash_t *sfl_info = NULL; 227#endif 228 229 bootdev = soc_boot_dev((void *)sih); 230#ifdef NFLASH_SUPPORT 231 if (bootdev == SOC_BOOTDEV_NANDFLASH) { 232 /* Init nand anyway */ 233 nfl_info = hndnand_init(sih); 234 if (nfl_info) 235 flbase = nfl_info->phybase; 236 } 237 else 238#endif /* NFLASH_SUPPORT */ 239 if (bootdev == SOC_BOOTDEV_SFLASH) { 240#ifdef _CFE_ 241 /* Init nand anyway */ 242 sfl_info = hndsflash_init(sih); 243 if (sfl_info) { 244 flbase = sfl_info->phybase; 245 lim = sfl_info->size; 246 } 247#else 248 if (sih->ccrev == 42) 249 flbase = SI_NS_NORFLASH; 250#endif 251 } 252 253 if (!embonly) { 254 *isemb = FALSE; 255#ifdef NFLASH_SUPPORT 256 if (nfl_info) { 257 uint32 blocksize; 258 259 blocksize = nfl_info->blocksize; 260 off = blocksize; 261 for (; off < nfl_boot_size(nfl_info); off += blocksize) { 262 if (hndnand_checkbadb(nfl_info, off) != 0) 263 continue; 264 nvh = (struct nvram_header *)OSL_UNCACHED(flbase + off); 265 if (nvh->magic != NVRAM_MAGIC) 266 continue; 267 268 /* Read into the nand_nvram */ 269 if ((nvh = nand_find_nvram(nfl_info, off)) == NULL) 270 continue; 271 if (nvram_calc_crc(nvh) == (uint8)nvh->crc_ver_init) 272 return nvh; 273 } 274 } 275 else 276#endif /* NFLASH_SUPPORT */ 277 { 278 off = FLASH_MIN; 279 while (off <= lim) { 280 nvh = (struct nvram_header *) 281 OSL_UNCACHED(flbase + off - MAX_NVRAM_SPACE); 282 if (nvh->magic == NVRAM_MAGIC) { 283 if (nvram_calc_crc(nvh) == (uint8) nvh->crc_ver_init) { 284 return (nvh); 285 } 286 } 287 off <<= 1; 288 } 289 } 290#ifdef BCMDBG 291 printf("find_nvram: nvram not found, trying embedded nvram next\n"); 292#endif /* BCMDBG */ 293 } 294 295 /* 296 * Provide feedback to user when nvram corruption detected. 297 * Must be non-BCMDBG for customer release. 298 */ 299 printf("Corrupt NVRAM found, trying embedded NVRAM next.\n"); 300 301 /* Now check embedded nvram */ 302 *isemb = TRUE; 303 nvh = (struct nvram_header *)OSL_UNCACHED(flbase + (4 * 1024)); 304 if (nvh->magic == NVRAM_MAGIC) 305 return (nvh); 306 nvh = (struct nvram_header *)OSL_UNCACHED(flbase + 1024); 307 if (nvh->magic == NVRAM_MAGIC) 308 return (nvh); 309#ifdef _CFE_ 310 nvh = (struct nvram_header *)embedded_nvram; 311 if (nvh->magic == NVRAM_MAGIC) 312 return (nvh); 313#endif 314 printf("find_nvram: no nvram found\n"); 315 return (NULL); 316} 317 318int 319BCMATTACHFN(nvram_init)(void *si) 320{ 321 bool isemb; 322 int ret; 323 si_t *sih; 324 static int nvram_status = -1; 325 326#ifdef __ECOS 327 if (!kernel_initial) 328 return 0; 329#endif 330 331 /* Check for previous 'restore defaults' condition */ 332 if (nvram_status == 1) 333 return 1; 334 335 /* Check whether nvram already initilized */ 336 if (nvram_status == 0 && !nvram_do_reset) 337 return 0; 338 339 sih = (si_t *)si; 340 341 /* Restore defaults from embedded NVRAM if button held down */ 342 if (nvram_do_reset) { 343 /* Initialize with embedded NVRAM */ 344 nvram_header = find_nvram(sih, TRUE, &isemb); 345 ret = _nvram_init(si, 0); 346 if (ret == 0) { 347 nvram_status = 1; 348 return 1; 349 } 350 nvram_status = -1; 351 _nvram_exit(); 352 } 353 354 /* Find NVRAM */ 355 nvram_header = find_nvram(sih, FALSE, &isemb); 356 ret = _nvram_init(si, 0); 357 if (ret == 0) { 358 /* Restore defaults if embedded NVRAM used */ 359 if (nvram_header && isemb) { 360 ret = 1; 361 } 362 } 363 nvram_status = ret; 364 return ret; 365} 366 367int 368BCMINITFN(nvram_append)(void *si, char *vars, uint varsz) 369{ 370 return 0; 371} 372 373void 374BCMINITFN(nvram_exit)(void *si) 375{ 376 si_t *sih; 377 378 sih = (si_t *)si; 379 380 _nvram_exit(); 381} 382 383/* LZMA need to be able to allocate memory, 384 * so set it up to use the OSL memory routines, 385 * only the linux debug osl uses the osh on malloc and the osh and size on 386 * free, and the debug code checks if they are valid, so pass NULL as the osh 387 * to tell the OSL that we don't have a valid osh 388 */ 389static void *SzAlloc(void *p, size_t size) { p = p; return MALLOC(NULL, size); } 390static void SzFree(void *p, void *address) { p = p; MFREE(NULL, address, 0); } 391static ISzAlloc g_Alloc = { SzAlloc, SzFree }; 392 393int 394BCMINITFN(_nvram_read)(void *buf, int idx) 395{ 396 uint32 *src, *dst; 397 uint i; 398 399 if (!nvram_header) 400 return -19; /* -ENODEV */ 401 402#if defined(_CFE_) && defined(BCM_DEVINFO) 403 if ((!devinfo_nvram_header) && (idx == 1)) { 404 return -19; /* -ENODEV */ 405 } 406 407 src = idx == 0 ? (uint32 *) nvram_header : (uint32 *) devinfo_nvram_nvh; 408#else 409 src = (uint32 *) nvram_header; 410#endif /* _CFE_ && BCM_DEVINFO */ 411 412 dst = (uint32 *) buf; 413 414 for (i = 0; i < sizeof(struct nvram_header); i += 4) 415 *dst++ = *src++; 416 417 /* Since we know what the first 3 bytes of the lzma properties 418 * should be based on what we used to compress, check them 419 * to see if we need to decompress (uncompressed this would show up a 420 * a single [ and then the end of nvram marker so its invalid in an 421 * uncompressed nvram block 422 */ 423 if ((((unsigned char *)src)[0] == 0x5d) && 424 (((unsigned char *)src)[1] == 0) && 425 (((unsigned char *)src)[2] == 0)) { 426 unsigned int dstlen = nvram_header->len; 427 unsigned int srclen = MAX_NVRAM_SPACE-LZMA_PROPS_SIZE-NVRAM_HEADER_SIZE; 428 unsigned char *cp = (unsigned char *)src; 429 CLzmaDec state; 430 SRes res; 431 ELzmaStatus status; 432 433 LzmaDec_Construct(&state); 434 res = LzmaDec_Allocate(&state, cp, LZMA_PROPS_SIZE, &g_Alloc); 435 if (res != SZ_OK) { 436 printf("Error Initializing LZMA Library\n"); 437 return -19; 438 } 439 LzmaDec_Init(&state); 440 res = LzmaDec_DecodeToBuf(&state, 441 (unsigned char *)dst, &dstlen, 442 &cp[LZMA_PROPS_SIZE], &srclen, 443 LZMA_FINISH_ANY, 444 &status); 445 446 LzmaDec_Free(&state, &g_Alloc); 447 if (res != SZ_OK) { 448 printf("Error Decompressing eNVRAM\n"); 449 return -19; 450 } 451 } else { 452 for (; i < nvram_header->len && i < MAX_NVRAM_SPACE; i += 4) 453 *dst++ = ltoh32(*src++); 454 } 455 return 0; 456} 457 458struct nvram_tuple * 459BCMINITFN(_nvram_realloc)(struct nvram_tuple *t, const char *name, const char *value) 460{ 461 if (!(t = MALLOC(NULL, sizeof(struct nvram_tuple) + strlen(name) + 1 + 462 strlen(value) + 1))) { 463 printf("_nvram_realloc: our of memory\n"); 464 return NULL; 465 } 466 467 /* Copy name */ 468 t->name = (char *) &t[1]; 469 strcpy(t->name, name); 470 471 /* Copy value */ 472 t->value = t->name + strlen(name) + 1; 473 strcpy(t->value, value); 474 475 return t; 476} 477 478void 479BCMINITFN(_nvram_free)(struct nvram_tuple *t) 480{ 481 if (t) 482 MFREE(NULL, t, sizeof(struct nvram_tuple) + strlen(t->name) + 1 + 483 strlen(t->value) + 1); 484} 485 486#ifdef __ECOS 487int 488BCMINITFN(nvram_reinit_hash)(void) 489{ 490 struct nvram_header *header; 491 int ret; 492 493 if (!(header = (struct nvram_header *) MALLOC(NULL, MAX_NVRAM_SPACE))) { 494 printf("nvram_reinit_hash: out of memory\n"); 495 return -12; /* -ENOMEM */ 496 } 497 498 NVRAM_LOCK(); 499 500 /* Regenerate NVRAM */ 501 ret = _nvram_commit(header); 502 503 NVRAM_UNLOCK(); 504 MFREE(NULL, header, MAX_NVRAM_SPACE); 505 return ret; 506} 507#endif /* __ECOS */ 508 509int 510BCMINITFN(nvram_commit_internal)(bool nvram_corrupt) 511{ 512 struct nvram_header *header; 513 int ret; 514 uint32 *src, *dst; 515 uint i; 516 517 if (!(header = (struct nvram_header *) MALLOC(NULL, MAX_NVRAM_SPACE))) { 518 printf("nvram_commit: out of memory\n"); 519 return -12; /* -ENOMEM */ 520 } 521 522 NVRAM_LOCK(); 523 524 /* Regenerate NVRAM */ 525 ret = _nvram_commit(header); 526 if (ret) 527 goto done; 528 529 src = (uint32 *) &header[1]; 530 dst = src; 531 532 for (i = sizeof(struct nvram_header); i < header->len && i < MAX_NVRAM_SPACE; i += 4) 533 *dst++ = htol32(*src++); 534 535#ifdef _CFE_ 536 if ((ret = cfe_open(flashdrv_nvram)) >= 0) { 537 if (nvram_corrupt) { 538 printf("Corrupting NVRAM...\n"); 539 header->magic = NVRAM_INVALID_MAGIC; 540 } 541 cfe_writeblk(ret, 0, (unsigned char *) header, header->len); 542 cfe_close(ret); 543 } 544#else 545 if (sysFlashInit(NULL) == 0) { 546 /* set/write invalid MAGIC # (in case writing image fails/is interrupted) 547 * write the NVRAM image to flash(with invalid magic) 548 * set/write valid MAGIC # 549 */ 550 header->magic = NVRAM_CLEAR_MAGIC; 551 nvWriteChars((unsigned char *)&header->magic, sizeof(header->magic)); 552 553 header->magic = NVRAM_INVALID_MAGIC; 554 nvWrite((unsigned short *) header, MAX_NVRAM_SPACE); 555 556 header->magic = NVRAM_MAGIC; 557 nvWriteChars((unsigned char *)&header->magic, sizeof(header->magic)); 558 } 559#endif /* ifdef _CFE_ */ 560 561done: 562 NVRAM_UNLOCK(); 563 MFREE(NULL, header, MAX_NVRAM_SPACE); 564 return ret; 565} 566 567int 568BCMINITFN(nvram_commit)(void) 569{ 570 /* do not corrupt nvram */ 571 return nvram_commit_internal(FALSE); 572} 573 574#if defined(_CFE_) && defined(BCM_DEVINFO) 575static struct nvram_header * 576BCMINITFN(find_devinfo_nvram)(si_t *sih) 577{ 578 int cfe_fd, ret; 579 580 if (devinfo_nvram_header != NULL) { 581 return (devinfo_nvram_header); 582 } 583 584 if ((cfe_fd = cfe_open(devinfo_flashdrv_nvram)) < 0) { 585 return NULL; 586 } 587 588 ret = cfe_read(cfe_fd, (unsigned char *)devinfo_nvram_nvh, NVRAM_SPACE); 589 if (ret >= 0) { 590 devinfo_nvram_header = (struct nvram_header *) devinfo_nvram_nvh; 591 } 592 593 cfe_close(cfe_fd); 594 595 return (devinfo_nvram_header); 596} 597 598int 599BCMINITFN(devinfo_nvram_init)(void *si) 600{ 601 int ret; 602 si_t *sih = (si_t *)si; 603 604 nvram_header = find_devinfo_nvram(sih); 605 _nvram_hash_select(1); 606 ret = _nvram_init(si, 1); 607 _nvram_hash_select(0); 608 609 return (ret); 610} 611 612/* sync nvram hash table with devinfo nvram hash table, and commit nvram */ 613int 614BCMINITFN(devinfo_nvram_sync)(void) 615{ 616 _nvram_hash_sync(); 617 nvram_commit(); 618 619 return (0); 620} 621#endif /* _CFE_ && BCM_DEVINFO */ 622