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