1 /* 2 * (C) Copyright 2000-2010 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * (C) Copyright 2008 6 * Guennadi Liakhovetski, DENX Software Engineering, lg@denx.de. 7 * 8 * See file CREDITS for list of people who contributed to this 9 * project. 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License as 13 * published by the Free Software Foundation; either version 2 of 14 * the License, or (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 24 * MA 02111-1307 USA 25 */ 26 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <stddef.h> 32 #include <string.h> 33 #include <sys/types.h> 34 #include <sys/ioctl.h> 35 #include <sys/stat.h> 36 #include <unistd.h> 37 38 #ifdef MTD_OLD 39 # include <stdint.h> 40 # include <linux/mtd/mtd.h> 41 #else 42 # define __user /* nothing */ 43 # include <mtd/mtd-user.h> 44 #endif 45 46 #include "fw_env.h" 47 48 #define WHITESPACE(c) ((c == '\t') || (c == ' ')) 49 50 #define min(x, y) ({ \ 51 typeof(x) _min1 = (x); \ 52 typeof(y) _min2 = (y); \ 53 (void) (&_min1 == &_min2); \ 54 _min1 < _min2 ? _min1 : _min2; }) 55 56 struct envdev_s { 57 char devname[16]; /* Device name */ 58 ulong devoff; /* Device offset */ 59 ulong env_size; /* environment size */ 60 ulong erase_size; /* device erase size */ 61 ulong env_sectors; /* number of environment sectors */ 62 uint8_t mtd_type; /* type of the MTD device */ 63 }; 64 65 static struct envdev_s envdevices[2] = 66 { 67 { 68 .mtd_type = MTD_ABSENT, 69 }, { 70 .mtd_type = MTD_ABSENT, 71 }, 72 }; 73 static int dev_current; 74 75 #define DEVNAME(i) envdevices[(i)].devname 76 #define DEVOFFSET(i) envdevices[(i)].devoff 77 #define ENVSIZE(i) envdevices[(i)].env_size 78 #define DEVESIZE(i) envdevices[(i)].erase_size 79 #define ENVSECTORS(i) envdevices[(i)].env_sectors 80 #define DEVTYPE(i) envdevices[(i)].mtd_type 81 82 #define CUR_ENVSIZE ENVSIZE(dev_current) 83 84 #define ENV_SIZE getenvsize() 85 86 struct env_image_single { 87 uint32_t crc; /* CRC32 over data bytes */ 88 char data[]; 89 }; 90 91 struct env_image_redundant { 92 uint32_t crc; /* CRC32 over data bytes */ 93 unsigned char flags; /* active or obsolete */ 94 char data[]; 95 }; 96 97 enum flag_scheme { 98 FLAG_NONE, 99 FLAG_BOOLEAN, 100 FLAG_INCREMENTAL, 101 }; 102 103 struct environment { 104 void *image; 105 uint32_t *crc; 106 unsigned char *flags; 107 char *data; 108 enum flag_scheme flag_scheme; 109 }; 110 111 static struct environment environment = { 112 .flag_scheme = FLAG_NONE, 113 }; 114 115 static int HaveRedundEnv = 0; 116 117 static unsigned char active_flag = 1; 118 /* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */ 119 static unsigned char obsolete_flag = 0; 120 121 122 static char default_environment[] = { 123 #if defined(CONFIG_BOOTARGS) 124 "bootargs=" CONFIG_BOOTARGS "\0" 125 #endif 126 #if defined(CONFIG_BOOTCOMMAND) 127 "bootcmd=" CONFIG_BOOTCOMMAND "\0" 128 #endif 129 #if defined(CONFIG_RAMBOOTCOMMAND) 130 "ramboot=" CONFIG_RAMBOOTCOMMAND "\0" 131 #endif 132 #if defined(CONFIG_NFSBOOTCOMMAND) 133 "nfsboot=" CONFIG_NFSBOOTCOMMAND "\0" 134 #endif 135 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 136 "bootdelay=" __stringify(CONFIG_BOOTDELAY) "\0" 137 #endif 138 #if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0) 139 "baudrate=" __stringify(CONFIG_BAUDRATE) "\0" 140 #endif 141 #ifdef CONFIG_LOADS_ECHO 142 "loads_echo=" __stringify(CONFIG_LOADS_ECHO) "\0" 143 #endif 144 #ifdef CONFIG_ETHADDR 145 "ethaddr=" __stringify(CONFIG_ETHADDR) "\0" 146 #endif 147 #ifdef CONFIG_ETH1ADDR 148 "eth1addr=" __stringify(CONFIG_ETH1ADDR) "\0" 149 #endif 150 #ifdef CONFIG_ETH2ADDR 151 "eth2addr=" __stringify(CONFIG_ETH2ADDR) "\0" 152 #endif 153 #ifdef CONFIG_ETH3ADDR 154 "eth3addr=" __stringify(CONFIG_ETH3ADDR) "\0" 155 #endif 156 #ifdef CONFIG_ETH4ADDR 157 "eth4addr=" __stringify(CONFIG_ETH4ADDR) "\0" 158 #endif 159 #ifdef CONFIG_ETH5ADDR 160 "eth5addr=" __stringify(CONFIG_ETH5ADDR) "\0" 161 #endif 162 #ifdef CONFIG_ETHPRIME 163 "ethprime=" CONFIG_ETHPRIME "\0" 164 #endif 165 #ifdef CONFIG_IPADDR 166 "ipaddr=" __stringify(CONFIG_IPADDR) "\0" 167 #endif 168 #ifdef CONFIG_SERVERIP 169 "serverip=" __stringify(CONFIG_SERVERIP) "\0" 170 #endif 171 #ifdef CONFIG_SYS_AUTOLOAD 172 "autoload=" CONFIG_SYS_AUTOLOAD "\0" 173 #endif 174 #ifdef CONFIG_ROOTPATH 175 "rootpath=" CONFIG_ROOTPATH "\0" 176 #endif 177 #ifdef CONFIG_GATEWAYIP 178 "gatewayip=" __stringify(CONFIG_GATEWAYIP) "\0" 179 #endif 180 #ifdef CONFIG_NETMASK 181 "netmask=" __stringify(CONFIG_NETMASK) "\0" 182 #endif 183 #ifdef CONFIG_HOSTNAME 184 "hostname=" __stringify(CONFIG_HOSTNAME) "\0" 185 #endif 186 #ifdef CONFIG_BOOTFILE 187 "bootfile=" CONFIG_BOOTFILE "\0" 188 #endif 189 #ifdef CONFIG_LOADADDR 190 "loadaddr=" __stringify(CONFIG_LOADADDR) "\0" 191 #endif 192 #ifdef CONFIG_PREBOOT 193 "preboot=" CONFIG_PREBOOT "\0" 194 #endif 195 #ifdef CONFIG_CLOCKS_IN_MHZ 196 "clocks_in_mhz=" "1" "\0" 197 #endif 198 #if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0) 199 "pcidelay=" __stringify(CONFIG_PCI_BOOTDELAY) "\0" 200 #endif 201 #ifdef CONFIG_ENV_VARS_UBOOT_CONFIG 202 "arch=" CONFIG_SYS_ARCH "\0" 203 "cpu=" CONFIG_SYS_CPU "\0" 204 "board=" CONFIG_SYS_BOARD "\0" 205 #ifdef CONFIG_SYS_VENDOR 206 "vendor=" CONFIG_SYS_VENDOR "\0" 207 #endif 208 #ifdef CONFIG_SYS_SOC 209 "soc=" CONFIG_SYS_SOC "\0" 210 #endif 211 #endif 212 #ifdef CONFIG_EXTRA_ENV_SETTINGS 213 CONFIG_EXTRA_ENV_SETTINGS 214 #endif 215 "\0" /* Termimate struct environment data with 2 NULs */ 216 }; 217 218 static int flash_io (int mode); 219 static char *envmatch (char * s1, char * s2); 220 static int parse_config (void); 221 222 #if defined(CONFIG_FILE) 223 static int get_config (char *); 224 #endif 225 static inline ulong getenvsize (void) 226 { 227 ulong rc = CUR_ENVSIZE - sizeof(long); 228 229 if (HaveRedundEnv) 230 rc -= sizeof (char); 231 return rc; 232 } 233 234 static char *fw_string_blank(char *s, int noblank) 235 { 236 int i; 237 int len = strlen(s); 238 239 for (i = 0; i < len; i++, s++) { 240 if ((noblank && !WHITESPACE(*s)) || 241 (!noblank && WHITESPACE(*s))) 242 break; 243 } 244 if (i == len) 245 return NULL; 246 247 return s; 248 } 249 250 /* 251 * Search the environment for a variable. 252 * Return the value, if found, or NULL, if not found. 253 */ 254 char *fw_getenv (char *name) 255 { 256 char *env, *nxt; 257 258 if (fw_env_open()) 259 return NULL; 260 261 for (env = environment.data; *env; env = nxt + 1) { 262 char *val; 263 264 for (nxt = env; *nxt; ++nxt) { 265 if (nxt >= &environment.data[ENV_SIZE]) { 266 fprintf (stderr, "## Error: " 267 "environment not terminated\n"); 268 return NULL; 269 } 270 } 271 val = envmatch (name, env); 272 if (!val) 273 continue; 274 return val; 275 } 276 return NULL; 277 } 278 279 /* 280 * Print the current definition of one, or more, or all 281 * environment variables 282 */ 283 int fw_printenv (int argc, char *argv[]) 284 { 285 char *env, *nxt; 286 int i, n_flag; 287 int rc = 0; 288 289 if (fw_env_open()) 290 return -1; 291 292 if (argc == 1) { /* Print all env variables */ 293 for (env = environment.data; *env; env = nxt + 1) { 294 for (nxt = env; *nxt; ++nxt) { 295 if (nxt >= &environment.data[ENV_SIZE]) { 296 fprintf (stderr, "## Error: " 297 "environment not terminated\n"); 298 return -1; 299 } 300 } 301 302 printf ("%s\n", env); 303 } 304 return 0; 305 } 306 307 if (strcmp (argv[1], "-n") == 0) { 308 n_flag = 1; 309 ++argv; 310 --argc; 311 if (argc != 2) { 312 fprintf (stderr, "## Error: " 313 "`-n' option requires exactly one argument\n"); 314 return -1; 315 } 316 } else { 317 n_flag = 0; 318 } 319 320 for (i = 1; i < argc; ++i) { /* print single env variables */ 321 char *name = argv[i]; 322 char *val = NULL; 323 324 for (env = environment.data; *env; env = nxt + 1) { 325 326 for (nxt = env; *nxt; ++nxt) { 327 if (nxt >= &environment.data[ENV_SIZE]) { 328 fprintf (stderr, "## Error: " 329 "environment not terminated\n"); 330 return -1; 331 } 332 } 333 val = envmatch (name, env); 334 if (val) { 335 if (!n_flag) { 336 fputs (name, stdout); 337 putc ('=', stdout); 338 } 339 puts (val); 340 break; 341 } 342 } 343 if (!val) { 344 fprintf (stderr, "## Error: \"%s\" not defined\n", name); 345 rc = -1; 346 } 347 } 348 349 return rc; 350 } 351 352 int fw_env_close(void) 353 { 354 /* 355 * Update CRC 356 */ 357 *environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE); 358 359 /* write environment back to flash */ 360 if (flash_io(O_RDWR)) { 361 fprintf(stderr, 362 "Error: can't write fw_env to flash\n"); 363 return -1; 364 } 365 366 return 0; 367 } 368 369 370 /* 371 * Set/Clear a single variable in the environment. 372 * This is called in sequence to update the environment 373 * in RAM without updating the copy in flash after each set 374 */ 375 int fw_env_write(char *name, char *value) 376 { 377 int len; 378 char *env, *nxt; 379 char *oldval = NULL; 380 381 /* 382 * search if variable with this name already exists 383 */ 384 for (nxt = env = environment.data; *env; env = nxt + 1) { 385 for (nxt = env; *nxt; ++nxt) { 386 if (nxt >= &environment.data[ENV_SIZE]) { 387 fprintf(stderr, "## Error: " 388 "environment not terminated\n"); 389 errno = EINVAL; 390 return -1; 391 } 392 } 393 if ((oldval = envmatch (name, env)) != NULL) 394 break; 395 } 396 397 /* 398 * Delete any existing definition 399 */ 400 if (oldval) { 401 #ifndef CONFIG_ENV_OVERWRITE 402 /* 403 * Ethernet Address and serial# can be set only once 404 */ 405 if ( 406 (strcmp(name, "serial#") == 0) || 407 ((strcmp(name, "ethaddr") == 0) 408 #if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) 409 && (strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0) 410 #endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */ 411 ) ) { 412 fprintf (stderr, "Can't overwrite \"%s\"\n", name); 413 errno = EROFS; 414 return -1; 415 } 416 #endif /* CONFIG_ENV_OVERWRITE */ 417 418 if (*++nxt == '\0') { 419 *env = '\0'; 420 } else { 421 for (;;) { 422 *env = *nxt++; 423 if ((*env == '\0') && (*nxt == '\0')) 424 break; 425 ++env; 426 } 427 } 428 *++env = '\0'; 429 } 430 431 /* Delete only ? */ 432 if (!value || !strlen(value)) 433 return 0; 434 435 /* 436 * Append new definition at the end 437 */ 438 for (env = environment.data; *env || *(env + 1); ++env); 439 if (env > environment.data) 440 ++env; 441 /* 442 * Overflow when: 443 * "name" + "=" + "val" +"\0\0" > CUR_ENVSIZE - (env-environment) 444 */ 445 len = strlen (name) + 2; 446 /* add '=' for first arg, ' ' for all others */ 447 len += strlen(value) + 1; 448 449 if (len > (&environment.data[ENV_SIZE] - env)) { 450 fprintf (stderr, 451 "Error: environment overflow, \"%s\" deleted\n", 452 name); 453 return -1; 454 } 455 456 while ((*env = *name++) != '\0') 457 env++; 458 *env = '='; 459 while ((*++env = *value++) != '\0') 460 ; 461 462 /* end is marked with double '\0' */ 463 *++env = '\0'; 464 465 return 0; 466 } 467 468 /* 469 * Deletes or sets environment variables. Returns -1 and sets errno error codes: 470 * 0 - OK 471 * EINVAL - need at least 1 argument 472 * EROFS - certain variables ("ethaddr", "serial#") cannot be 473 * modified or deleted 474 * 475 */ 476 int fw_setenv(int argc, char *argv[]) 477 { 478 int i, len; 479 char *name; 480 char *value = NULL; 481 char *tmpval = NULL; 482 483 if (argc < 2) { 484 errno = EINVAL; 485 return -1; 486 } 487 488 if (fw_env_open()) { 489 fprintf(stderr, "Error: environment not initialized\n"); 490 return -1; 491 } 492 493 name = argv[1]; 494 495 len = strlen(name) + 2; 496 for (i = 2; i < argc; ++i) 497 len += strlen(argv[i]) + 1; 498 499 /* Allocate enough place to the data string */ 500 for (i = 2; i < argc; ++i) { 501 char *val = argv[i]; 502 if (!value) { 503 value = (char *)malloc(len - strlen(name)); 504 if (!value) { 505 fprintf(stderr, 506 "Cannot malloc %zu bytes: %s\n", 507 len - strlen(name), strerror(errno)); 508 return -1; 509 } 510 memset(value, 0, len - strlen(name)); 511 tmpval = value; 512 } 513 if (i != 2) 514 *tmpval++ = ' '; 515 while (*val != '\0') 516 *tmpval++ = *val++; 517 } 518 519 fw_env_write(name, value); 520 521 if (value) 522 free(value); 523 524 return fw_env_close(); 525 } 526 527 /* 528 * Parse a file and configure the u-boot variables. 529 * The script file has a very simple format, as follows: 530 * 531 * Each line has a couple with name, value: 532 * <white spaces>variable_name<white spaces>variable_value 533 * 534 * Both variable_name and variable_value are interpreted as strings. 535 * Any character after <white spaces> and before ending \r\n is interpreted 536 * as variable's value (no comment allowed on these lines !) 537 * 538 * Comments are allowed if the first character in the line is # 539 * 540 * Returns -1 and sets errno error codes: 541 * 0 - OK 542 * -1 - Error 543 */ 544 int fw_parse_script(char *fname) 545 { 546 FILE *fp; 547 char dump[1024]; /* Maximum line length in the file */ 548 char *name; 549 char *val; 550 int lineno = 0; 551 int len; 552 int ret = 0; 553 554 if (fw_env_open()) { 555 fprintf(stderr, "Error: environment not initialized\n"); 556 return -1; 557 } 558 559 if (strcmp(fname, "-") == 0) 560 fp = stdin; 561 else { 562 fp = fopen(fname, "r"); 563 if (fp == NULL) { 564 fprintf(stderr, "I cannot open %s for reading\n", 565 fname); 566 return -1; 567 } 568 } 569 570 while (fgets(dump, sizeof(dump), fp)) { 571 lineno++; 572 len = strlen(dump); 573 574 /* 575 * Read a whole line from the file. If the line is too long 576 * or is not terminated, reports an error and exit. 577 */ 578 if (dump[len - 1] != '\n') { 579 fprintf(stderr, 580 "Line %d not corrected terminated or too long\n", 581 lineno); 582 ret = -1; 583 break; 584 } 585 586 /* Drop ending line feed / carriage return */ 587 while (len > 0 && (dump[len - 1] == '\n' || 588 dump[len - 1] == '\r')) { 589 dump[len - 1] = '\0'; 590 len--; 591 } 592 593 /* Skip comment or empty lines */ 594 if ((len == 0) || dump[0] == '#') 595 continue; 596 597 /* 598 * Search for variable's name, 599 * remove leading whitespaces 600 */ 601 name = fw_string_blank(dump, 1); 602 if (!name) 603 continue; 604 605 /* The first white space is the end of variable name */ 606 val = fw_string_blank(name, 0); 607 len = strlen(name); 608 if (val) { 609 *val++ = '\0'; 610 if ((val - name) < len) 611 val = fw_string_blank(val, 1); 612 else 613 val = NULL; 614 } 615 616 #ifdef DEBUG 617 fprintf(stderr, "Setting %s : %s\n", 618 name, val ? val : " removed"); 619 #endif 620 621 /* 622 * If there is an error setting a variable, 623 * try to save the environment and returns an error 624 */ 625 if (fw_env_write(name, val)) { 626 fprintf(stderr, 627 "fw_env_write returns with error : %s\n", 628 strerror(errno)); 629 ret = -1; 630 break; 631 } 632 633 } 634 635 /* Close file if not stdin */ 636 if (strcmp(fname, "-") != 0) 637 fclose(fp); 638 639 ret |= fw_env_close(); 640 641 return ret; 642 643 } 644 645 /* 646 * Test for bad block on NAND, just returns 0 on NOR, on NAND: 647 * 0 - block is good 648 * > 0 - block is bad 649 * < 0 - failed to test 650 */ 651 static int flash_bad_block (int fd, uint8_t mtd_type, loff_t *blockstart) 652 { 653 if (mtd_type == MTD_NANDFLASH) { 654 int badblock = ioctl (fd, MEMGETBADBLOCK, blockstart); 655 656 if (badblock < 0) { 657 perror ("Cannot read bad block mark"); 658 return badblock; 659 } 660 661 if (badblock) { 662 #ifdef DEBUG 663 fprintf (stderr, "Bad block at 0x%llx, " 664 "skipping\n", *blockstart); 665 #endif 666 return badblock; 667 } 668 } 669 670 return 0; 671 } 672 673 /* 674 * Read data from flash at an offset into a provided buffer. On NAND it skips 675 * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from 676 * the DEVOFFSET (dev) block. On NOR the loop is only run once. 677 */ 678 static int flash_read_buf (int dev, int fd, void *buf, size_t count, 679 off_t offset, uint8_t mtd_type) 680 { 681 size_t blocklen; /* erase / write length - one block on NAND, 682 0 on NOR */ 683 size_t processed = 0; /* progress counter */ 684 size_t readlen = count; /* current read length */ 685 off_t top_of_range; /* end of the last block we may use */ 686 off_t block_seek; /* offset inside the current block to the start 687 of the data */ 688 loff_t blockstart; /* running start of the current block - 689 MEMGETBADBLOCK needs 64 bits */ 690 int rc; 691 692 blockstart = (offset / DEVESIZE (dev)) * DEVESIZE (dev); 693 694 /* Offset inside a block */ 695 block_seek = offset - blockstart; 696 697 if (mtd_type == MTD_NANDFLASH) { 698 /* 699 * NAND: calculate which blocks we are reading. We have 700 * to read one block at a time to skip bad blocks. 701 */ 702 blocklen = DEVESIZE (dev); 703 704 /* 705 * To calculate the top of the range, we have to use the 706 * global DEVOFFSET (dev), which can be different from offset 707 */ 708 top_of_range = ((DEVOFFSET(dev) / blocklen) + 709 ENVSECTORS (dev)) * blocklen; 710 711 /* Limit to one block for the first read */ 712 if (readlen > blocklen - block_seek) 713 readlen = blocklen - block_seek; 714 } else { 715 blocklen = 0; 716 top_of_range = offset + count; 717 } 718 719 /* This only runs once on NOR flash */ 720 while (processed < count) { 721 rc = flash_bad_block (fd, mtd_type, &blockstart); 722 if (rc < 0) /* block test failed */ 723 return -1; 724 725 if (blockstart + block_seek + readlen > top_of_range) { 726 /* End of range is reached */ 727 fprintf (stderr, 728 "Too few good blocks within range\n"); 729 return -1; 730 } 731 732 if (rc) { /* block is bad */ 733 blockstart += blocklen; 734 continue; 735 } 736 737 /* 738 * If a block is bad, we retry in the next block at the same 739 * offset - see common/env_nand.c::writeenv() 740 */ 741 lseek (fd, blockstart + block_seek, SEEK_SET); 742 743 rc = read (fd, buf + processed, readlen); 744 if (rc != readlen) { 745 fprintf (stderr, "Read error on %s: %s\n", 746 DEVNAME (dev), strerror (errno)); 747 return -1; 748 } 749 #ifdef DEBUG 750 fprintf (stderr, "Read 0x%x bytes at 0x%llx\n", 751 rc, blockstart + block_seek); 752 #endif 753 processed += readlen; 754 readlen = min (blocklen, count - processed); 755 block_seek = 0; 756 blockstart += blocklen; 757 } 758 759 return processed; 760 } 761 762 /* 763 * Write count bytes at offset, but stay within ENVSECTORS (dev) sectors of 764 * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we 765 * erase and write the whole data at once. 766 */ 767 static int flash_write_buf (int dev, int fd, void *buf, size_t count, 768 off_t offset, uint8_t mtd_type) 769 { 770 void *data; 771 struct erase_info_user erase; 772 size_t blocklen; /* length of NAND block / NOR erase sector */ 773 size_t erase_len; /* whole area that can be erased - may include 774 bad blocks */ 775 size_t erasesize; /* erase / write length - one block on NAND, 776 whole area on NOR */ 777 size_t processed = 0; /* progress counter */ 778 size_t write_total; /* total size to actually write - excluding 779 bad blocks */ 780 off_t erase_offset; /* offset to the first erase block (aligned) 781 below offset */ 782 off_t block_seek; /* offset inside the erase block to the start 783 of the data */ 784 off_t top_of_range; /* end of the last block we may use */ 785 loff_t blockstart; /* running start of the current block - 786 MEMGETBADBLOCK needs 64 bits */ 787 int rc; 788 789 blocklen = DEVESIZE (dev); 790 791 top_of_range = ((DEVOFFSET(dev) / blocklen) + 792 ENVSECTORS (dev)) * blocklen; 793 794 erase_offset = (offset / blocklen) * blocklen; 795 796 /* Maximum area we may use */ 797 erase_len = top_of_range - erase_offset; 798 799 blockstart = erase_offset; 800 /* Offset inside a block */ 801 block_seek = offset - erase_offset; 802 803 /* 804 * Data size we actually have to write: from the start of the block 805 * to the start of the data, then count bytes of data, and to the 806 * end of the block 807 */ 808 write_total = ((block_seek + count + blocklen - 1) / 809 blocklen) * blocklen; 810 811 /* 812 * Support data anywhere within erase sectors: read out the complete 813 * area to be erased, replace the environment image, write the whole 814 * block back again. 815 */ 816 if (write_total > count) { 817 data = malloc (erase_len); 818 if (!data) { 819 fprintf (stderr, 820 "Cannot malloc %zu bytes: %s\n", 821 erase_len, strerror (errno)); 822 return -1; 823 } 824 825 rc = flash_read_buf (dev, fd, data, write_total, erase_offset, 826 mtd_type); 827 if (write_total != rc) 828 return -1; 829 830 /* Overwrite the old environment */ 831 memcpy (data + block_seek, buf, count); 832 } else { 833 /* 834 * We get here, iff offset is block-aligned and count is a 835 * multiple of blocklen - see write_total calculation above 836 */ 837 data = buf; 838 } 839 840 if (mtd_type == MTD_NANDFLASH) { 841 /* 842 * NAND: calculate which blocks we are writing. We have 843 * to write one block at a time to skip bad blocks. 844 */ 845 erasesize = blocklen; 846 } else { 847 erasesize = erase_len; 848 } 849 850 erase.length = erasesize; 851 852 /* This only runs once on NOR flash and SPI-dataflash */ 853 while (processed < write_total) { 854 rc = flash_bad_block (fd, mtd_type, &blockstart); 855 if (rc < 0) /* block test failed */ 856 return rc; 857 858 if (blockstart + erasesize > top_of_range) { 859 fprintf (stderr, "End of range reached, aborting\n"); 860 return -1; 861 } 862 863 if (rc) { /* block is bad */ 864 blockstart += blocklen; 865 continue; 866 } 867 868 erase.start = blockstart; 869 ioctl (fd, MEMUNLOCK, &erase); 870 871 /* Dataflash does not need an explicit erase cycle */ 872 if (mtd_type != MTD_DATAFLASH) 873 if (ioctl (fd, MEMERASE, &erase) != 0) { 874 fprintf (stderr, "MTD erase error on %s: %s\n", 875 DEVNAME (dev), 876 strerror (errno)); 877 return -1; 878 } 879 880 if (lseek (fd, blockstart, SEEK_SET) == -1) { 881 fprintf (stderr, 882 "Seek error on %s: %s\n", 883 DEVNAME (dev), strerror (errno)); 884 return -1; 885 } 886 887 #ifdef DEBUG 888 printf ("Write 0x%x bytes at 0x%llx\n", erasesize, blockstart); 889 #endif 890 if (write (fd, data + processed, erasesize) != erasesize) { 891 fprintf (stderr, "Write error on %s: %s\n", 892 DEVNAME (dev), strerror (errno)); 893 return -1; 894 } 895 896 ioctl (fd, MEMLOCK, &erase); 897 898 processed += blocklen; 899 block_seek = 0; 900 blockstart += blocklen; 901 } 902 903 if (write_total > count) 904 free (data); 905 906 return processed; 907 } 908 909 /* 910 * Set obsolete flag at offset - NOR flash only 911 */ 912 static int flash_flag_obsolete (int dev, int fd, off_t offset) 913 { 914 int rc; 915 struct erase_info_user erase; 916 917 erase.start = DEVOFFSET (dev); 918 erase.length = DEVESIZE (dev); 919 /* This relies on the fact, that obsolete_flag == 0 */ 920 rc = lseek (fd, offset, SEEK_SET); 921 if (rc < 0) { 922 fprintf (stderr, "Cannot seek to set the flag on %s \n", 923 DEVNAME (dev)); 924 return rc; 925 } 926 ioctl (fd, MEMUNLOCK, &erase); 927 rc = write (fd, &obsolete_flag, sizeof (obsolete_flag)); 928 ioctl (fd, MEMLOCK, &erase); 929 if (rc < 0) 930 perror ("Could not set obsolete flag"); 931 932 return rc; 933 } 934 935 static int flash_write (int fd_current, int fd_target, int dev_target) 936 { 937 int rc; 938 939 switch (environment.flag_scheme) { 940 case FLAG_NONE: 941 break; 942 case FLAG_INCREMENTAL: 943 (*environment.flags)++; 944 break; 945 case FLAG_BOOLEAN: 946 *environment.flags = active_flag; 947 break; 948 default: 949 fprintf (stderr, "Unimplemented flash scheme %u \n", 950 environment.flag_scheme); 951 return -1; 952 } 953 954 #ifdef DEBUG 955 printf ("Writing new environment at 0x%lx on %s\n", 956 DEVOFFSET (dev_target), DEVNAME (dev_target)); 957 #endif 958 rc = flash_write_buf(dev_target, fd_target, environment.image, 959 CUR_ENVSIZE, DEVOFFSET(dev_target), 960 DEVTYPE(dev_target)); 961 if (rc < 0) 962 return rc; 963 964 if (environment.flag_scheme == FLAG_BOOLEAN) { 965 /* Have to set obsolete flag */ 966 off_t offset = DEVOFFSET (dev_current) + 967 offsetof (struct env_image_redundant, flags); 968 #ifdef DEBUG 969 printf ("Setting obsolete flag in environment at 0x%lx on %s\n", 970 DEVOFFSET (dev_current), DEVNAME (dev_current)); 971 #endif 972 flash_flag_obsolete (dev_current, fd_current, offset); 973 } 974 975 return 0; 976 } 977 978 static int flash_read (int fd) 979 { 980 struct mtd_info_user mtdinfo; 981 int rc; 982 983 rc = ioctl (fd, MEMGETINFO, &mtdinfo); 984 if (rc < 0) { 985 perror ("Cannot get MTD information"); 986 return -1; 987 } 988 989 if (mtdinfo.type != MTD_NORFLASH && 990 mtdinfo.type != MTD_NANDFLASH && 991 mtdinfo.type != MTD_DATAFLASH) { 992 fprintf (stderr, "Unsupported flash type %u\n", mtdinfo.type); 993 return -1; 994 } 995 996 DEVTYPE(dev_current) = mtdinfo.type; 997 998 rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE, 999 DEVOFFSET (dev_current), mtdinfo.type); 1000 1001 return (rc != CUR_ENVSIZE) ? -1 : 0; 1002 } 1003 1004 static int flash_io (int mode) 1005 { 1006 int fd_current, fd_target, rc, dev_target; 1007 1008 /* dev_current: fd_current, erase_current */ 1009 fd_current = open (DEVNAME (dev_current), mode); 1010 if (fd_current < 0) { 1011 fprintf (stderr, 1012 "Can't open %s: %s\n", 1013 DEVNAME (dev_current), strerror (errno)); 1014 return -1; 1015 } 1016 1017 if (mode == O_RDWR) { 1018 if (HaveRedundEnv) { 1019 /* switch to next partition for writing */ 1020 dev_target = !dev_current; 1021 /* dev_target: fd_target, erase_target */ 1022 fd_target = open (DEVNAME (dev_target), mode); 1023 if (fd_target < 0) { 1024 fprintf (stderr, 1025 "Can't open %s: %s\n", 1026 DEVNAME (dev_target), 1027 strerror (errno)); 1028 rc = -1; 1029 goto exit; 1030 } 1031 } else { 1032 dev_target = dev_current; 1033 fd_target = fd_current; 1034 } 1035 1036 rc = flash_write (fd_current, fd_target, dev_target); 1037 1038 if (HaveRedundEnv) { 1039 if (close (fd_target)) { 1040 fprintf (stderr, 1041 "I/O error on %s: %s\n", 1042 DEVNAME (dev_target), 1043 strerror (errno)); 1044 rc = -1; 1045 } 1046 } 1047 } else { 1048 rc = flash_read (fd_current); 1049 } 1050 1051 exit: 1052 if (close (fd_current)) { 1053 fprintf (stderr, 1054 "I/O error on %s: %s\n", 1055 DEVNAME (dev_current), strerror (errno)); 1056 return -1; 1057 } 1058 1059 return rc; 1060 } 1061 1062 /* 1063 * s1 is either a simple 'name', or a 'name=value' pair. 1064 * s2 is a 'name=value' pair. 1065 * If the names match, return the value of s2, else NULL. 1066 */ 1067 1068 static char *envmatch (char * s1, char * s2) 1069 { 1070 1071 while (*s1 == *s2++) 1072 if (*s1++ == '=') 1073 return s2; 1074 if (*s1 == '\0' && *(s2 - 1) == '=') 1075 return s2; 1076 return NULL; 1077 } 1078 1079 /* 1080 * Prevent confusion if running from erased flash memory 1081 */ 1082 int fw_env_open(void) 1083 { 1084 int crc0, crc0_ok; 1085 unsigned char flag0; 1086 void *addr0; 1087 1088 int crc1, crc1_ok; 1089 unsigned char flag1; 1090 void *addr1; 1091 1092 struct env_image_single *single; 1093 struct env_image_redundant *redundant; 1094 1095 if (parse_config ()) /* should fill envdevices */ 1096 return -1; 1097 1098 addr0 = calloc(1, CUR_ENVSIZE); 1099 if (addr0 == NULL) { 1100 fprintf(stderr, 1101 "Not enough memory for environment (%ld bytes)\n", 1102 CUR_ENVSIZE); 1103 return -1; 1104 } 1105 1106 /* read environment from FLASH to local buffer */ 1107 environment.image = addr0; 1108 1109 if (HaveRedundEnv) { 1110 redundant = addr0; 1111 environment.crc = &redundant->crc; 1112 environment.flags = &redundant->flags; 1113 environment.data = redundant->data; 1114 } else { 1115 single = addr0; 1116 environment.crc = &single->crc; 1117 environment.flags = NULL; 1118 environment.data = single->data; 1119 } 1120 1121 dev_current = 0; 1122 if (flash_io (O_RDONLY)) 1123 return -1; 1124 1125 crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE); 1126 crc0_ok = (crc0 == *environment.crc); 1127 if (!HaveRedundEnv) { 1128 if (!crc0_ok) { 1129 fprintf (stderr, 1130 "Warning: Bad CRC, using default environment\n"); 1131 memcpy(environment.data, default_environment, sizeof default_environment); 1132 } 1133 } else { 1134 flag0 = *environment.flags; 1135 1136 dev_current = 1; 1137 addr1 = calloc(1, CUR_ENVSIZE); 1138 if (addr1 == NULL) { 1139 fprintf(stderr, 1140 "Not enough memory for environment (%ld bytes)\n", 1141 CUR_ENVSIZE); 1142 return -1; 1143 } 1144 redundant = addr1; 1145 1146 /* 1147 * have to set environment.image for flash_read(), careful - 1148 * other pointers in environment still point inside addr0 1149 */ 1150 environment.image = addr1; 1151 if (flash_io (O_RDONLY)) 1152 return -1; 1153 1154 /* Check flag scheme compatibility */ 1155 if (DEVTYPE(dev_current) == MTD_NORFLASH && 1156 DEVTYPE(!dev_current) == MTD_NORFLASH) { 1157 environment.flag_scheme = FLAG_BOOLEAN; 1158 } else if (DEVTYPE(dev_current) == MTD_NANDFLASH && 1159 DEVTYPE(!dev_current) == MTD_NANDFLASH) { 1160 environment.flag_scheme = FLAG_INCREMENTAL; 1161 } else if (DEVTYPE(dev_current) == MTD_DATAFLASH && 1162 DEVTYPE(!dev_current) == MTD_DATAFLASH) { 1163 environment.flag_scheme = FLAG_BOOLEAN; 1164 } else { 1165 fprintf (stderr, "Incompatible flash types!\n"); 1166 return -1; 1167 } 1168 1169 crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE); 1170 crc1_ok = (crc1 == redundant->crc); 1171 flag1 = redundant->flags; 1172 1173 if (crc0_ok && !crc1_ok) { 1174 dev_current = 0; 1175 } else if (!crc0_ok && crc1_ok) { 1176 dev_current = 1; 1177 } else if (!crc0_ok && !crc1_ok) { 1178 fprintf (stderr, 1179 "Warning: Bad CRC, using default environment\n"); 1180 memcpy (environment.data, default_environment, 1181 sizeof default_environment); 1182 dev_current = 0; 1183 } else { 1184 switch (environment.flag_scheme) { 1185 case FLAG_BOOLEAN: 1186 if (flag0 == active_flag && 1187 flag1 == obsolete_flag) { 1188 dev_current = 0; 1189 } else if (flag0 == obsolete_flag && 1190 flag1 == active_flag) { 1191 dev_current = 1; 1192 } else if (flag0 == flag1) { 1193 dev_current = 0; 1194 } else if (flag0 == 0xFF) { 1195 dev_current = 0; 1196 } else if (flag1 == 0xFF) { 1197 dev_current = 1; 1198 } else { 1199 dev_current = 0; 1200 } 1201 break; 1202 case FLAG_INCREMENTAL: 1203 if (flag0 == 255 && flag1 == 0) 1204 dev_current = 1; 1205 else if ((flag1 == 255 && flag0 == 0) || 1206 flag0 >= flag1) 1207 dev_current = 0; 1208 else /* flag1 > flag0 */ 1209 dev_current = 1; 1210 break; 1211 default: 1212 fprintf (stderr, "Unknown flag scheme %u \n", 1213 environment.flag_scheme); 1214 return -1; 1215 } 1216 } 1217 1218 /* 1219 * If we are reading, we don't need the flag and the CRC any 1220 * more, if we are writing, we will re-calculate CRC and update 1221 * flags before writing out 1222 */ 1223 if (dev_current) { 1224 environment.image = addr1; 1225 environment.crc = &redundant->crc; 1226 environment.flags = &redundant->flags; 1227 environment.data = redundant->data; 1228 free (addr0); 1229 } else { 1230 environment.image = addr0; 1231 /* Other pointers are already set */ 1232 free (addr1); 1233 } 1234 } 1235 return 0; 1236 } 1237 1238 1239 static int parse_config () 1240 { 1241 struct stat st; 1242 1243 #if defined(CONFIG_FILE) 1244 /* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */ 1245 if (get_config (CONFIG_FILE)) { 1246 fprintf (stderr, 1247 "Cannot parse config file: %s\n", strerror (errno)); 1248 return -1; 1249 } 1250 #else 1251 strcpy (DEVNAME (0), DEVICE1_NAME); 1252 DEVOFFSET (0) = DEVICE1_OFFSET; 1253 ENVSIZE (0) = ENV1_SIZE; 1254 /* Default values are: erase-size=env-size, #sectors=1 */ 1255 DEVESIZE (0) = ENVSIZE (0); 1256 ENVSECTORS (0) = 1; 1257 #ifdef DEVICE1_ESIZE 1258 DEVESIZE (0) = DEVICE1_ESIZE; 1259 #endif 1260 #ifdef DEVICE1_ENVSECTORS 1261 ENVSECTORS (0) = DEVICE1_ENVSECTORS; 1262 #endif 1263 1264 #ifdef HAVE_REDUND 1265 strcpy (DEVNAME (1), DEVICE2_NAME); 1266 DEVOFFSET (1) = DEVICE2_OFFSET; 1267 ENVSIZE (1) = ENV2_SIZE; 1268 /* Default values are: erase-size=env-size, #sectors=1 */ 1269 DEVESIZE (1) = ENVSIZE (1); 1270 ENVSECTORS (1) = 1; 1271 #ifdef DEVICE2_ESIZE 1272 DEVESIZE (1) = DEVICE2_ESIZE; 1273 #endif 1274 #ifdef DEVICE2_ENVSECTORS 1275 ENVSECTORS (1) = DEVICE2_ENVSECTORS; 1276 #endif 1277 HaveRedundEnv = 1; 1278 #endif 1279 #endif 1280 if (stat (DEVNAME (0), &st)) { 1281 fprintf (stderr, 1282 "Cannot access MTD device %s: %s\n", 1283 DEVNAME (0), strerror (errno)); 1284 return -1; 1285 } 1286 1287 if (HaveRedundEnv && stat (DEVNAME (1), &st)) { 1288 fprintf (stderr, 1289 "Cannot access MTD device %s: %s\n", 1290 DEVNAME (1), strerror (errno)); 1291 return -1; 1292 } 1293 return 0; 1294 } 1295 1296 #if defined(CONFIG_FILE) 1297 static int get_config (char *fname) 1298 { 1299 FILE *fp; 1300 int i = 0; 1301 int rc; 1302 char dump[128]; 1303 1304 fp = fopen (fname, "r"); 1305 if (fp == NULL) 1306 return -1; 1307 1308 while (i < 2 && fgets (dump, sizeof (dump), fp)) { 1309 /* Skip incomplete conversions and comment strings */ 1310 if (dump[0] == '#') 1311 continue; 1312 1313 rc = sscanf (dump, "%s %lx %lx %lx %lx", 1314 DEVNAME (i), 1315 &DEVOFFSET (i), 1316 &ENVSIZE (i), 1317 &DEVESIZE (i), 1318 &ENVSECTORS (i)); 1319 1320 if (rc < 3) 1321 continue; 1322 1323 if (rc < 4) 1324 /* Assume the erase size is the same as the env-size */ 1325 DEVESIZE(i) = ENVSIZE(i); 1326 1327 if (rc < 5) 1328 /* Default - 1 sector */ 1329 ENVSECTORS (i) = 1; 1330 1331 i++; 1332 } 1333 fclose (fp); 1334 1335 HaveRedundEnv = i - 1; 1336 if (!i) { /* No valid entries found */ 1337 errno = EINVAL; 1338 return -1; 1339 } else 1340 return 0; 1341 } 1342 #endif 1343