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 if (*++nxt == '\0') { 373 *env = '\0'; 374 } else { 375 for (;;) { 376 *env = *nxt++; 377 if ((*env == '\0') && (*nxt == '\0')) 378 break; 379 ++env; 380 } 381 } 382 *++env = '\0'; 383 } 384 385 /* Delete only ? */ 386 if (!value || !strlen(value)) 387 return 0; 388 389 /* 390 * Append new definition at the end 391 */ 392 for (env = environment.data; *env || *(env + 1); ++env); 393 if (env > environment.data) 394 ++env; 395 /* 396 * Overflow when: 397 * "name" + "=" + "val" +"\0\0" > CUR_ENVSIZE - (env-environment) 398 */ 399 len = strlen (name) + 2; 400 /* add '=' for first arg, ' ' for all others */ 401 len += strlen(value) + 1; 402 403 if (len > (&environment.data[ENV_SIZE] - env)) { 404 fprintf (stderr, 405 "Error: environment overflow, \"%s\" deleted\n", 406 name); 407 return -1; 408 } 409 410 while ((*env = *name++) != '\0') 411 env++; 412 *env = '='; 413 while ((*++env = *value++) != '\0') 414 ; 415 416 /* end is marked with double '\0' */ 417 *++env = '\0'; 418 419 return 0; 420 } 421 422 /* 423 * Deletes or sets environment variables. Returns -1 and sets errno error codes: 424 * 0 - OK 425 * EINVAL - need at least 1 argument 426 * EROFS - certain variables ("ethaddr", "serial#") cannot be 427 * modified or deleted 428 * 429 */ 430 int fw_setenv(int argc, char *argv[]) 431 { 432 int i; 433 size_t len; 434 char *name; 435 char *value = NULL; 436 437 if (argc < 2) { 438 errno = EINVAL; 439 return -1; 440 } 441 442 if (fw_env_open()) { 443 fprintf(stderr, "Error: environment not initialized\n"); 444 return -1; 445 } 446 447 name = argv[1]; 448 449 if (env_flags_validate_env_set_params(argc, argv) < 0) 450 return 1; 451 452 len = 0; 453 for (i = 2; i < argc; ++i) { 454 char *val = argv[i]; 455 size_t val_len = strlen(val); 456 457 if (value) 458 value[len - 1] = ' '; 459 value = realloc(value, len + val_len + 1); 460 if (!value) { 461 fprintf(stderr, 462 "Cannot malloc %zu bytes: %s\n", 463 len, strerror(errno)); 464 return -1; 465 } 466 467 memcpy(value + len, val, val_len); 468 len += val_len; 469 value[len++] = '\0'; 470 } 471 472 fw_env_write(name, value); 473 474 free(value); 475 476 return fw_env_close(); 477 } 478 479 /* 480 * Parse a file and configure the u-boot variables. 481 * The script file has a very simple format, as follows: 482 * 483 * Each line has a couple with name, value: 484 * <white spaces>variable_name<white spaces>variable_value 485 * 486 * Both variable_name and variable_value are interpreted as strings. 487 * Any character after <white spaces> and before ending \r\n is interpreted 488 * as variable's value (no comment allowed on these lines !) 489 * 490 * Comments are allowed if the first character in the line is # 491 * 492 * Returns -1 and sets errno error codes: 493 * 0 - OK 494 * -1 - Error 495 */ 496 int fw_parse_script(char *fname) 497 { 498 FILE *fp; 499 char dump[1024]; /* Maximum line length in the file */ 500 char *name; 501 char *val; 502 int lineno = 0; 503 int len; 504 int ret = 0; 505 506 if (fw_env_open()) { 507 fprintf(stderr, "Error: environment not initialized\n"); 508 return -1; 509 } 510 511 if (strcmp(fname, "-") == 0) 512 fp = stdin; 513 else { 514 fp = fopen(fname, "r"); 515 if (fp == NULL) { 516 fprintf(stderr, "I cannot open %s for reading\n", 517 fname); 518 return -1; 519 } 520 } 521 522 while (fgets(dump, sizeof(dump), fp)) { 523 lineno++; 524 len = strlen(dump); 525 526 /* 527 * Read a whole line from the file. If the line is too long 528 * or is not terminated, reports an error and exit. 529 */ 530 if (dump[len - 1] != '\n') { 531 fprintf(stderr, 532 "Line %d not corrected terminated or too long\n", 533 lineno); 534 ret = -1; 535 break; 536 } 537 538 /* Drop ending line feed / carriage return */ 539 while (len > 0 && (dump[len - 1] == '\n' || 540 dump[len - 1] == '\r')) { 541 dump[len - 1] = '\0'; 542 len--; 543 } 544 545 /* Skip comment or empty lines */ 546 if ((len == 0) || dump[0] == '#') 547 continue; 548 549 /* 550 * Search for variable's name, 551 * remove leading whitespaces 552 */ 553 name = fw_string_blank(dump, 1); 554 if (!name) 555 continue; 556 557 /* The first white space is the end of variable name */ 558 val = fw_string_blank(name, 0); 559 len = strlen(name); 560 if (val) { 561 *val++ = '\0'; 562 if ((val - name) < len) 563 val = fw_string_blank(val, 1); 564 else 565 val = NULL; 566 } 567 568 #ifdef DEBUG 569 fprintf(stderr, "Setting %s : %s\n", 570 name, val ? val : " removed"); 571 #endif 572 573 if (env_flags_validate_type(name, val) < 0) { 574 ret = -1; 575 break; 576 } 577 578 /* 579 * If there is an error setting a variable, 580 * try to save the environment and returns an error 581 */ 582 if (fw_env_write(name, val)) { 583 fprintf(stderr, 584 "fw_env_write returns with error : %s\n", 585 strerror(errno)); 586 ret = -1; 587 break; 588 } 589 590 } 591 592 /* Close file if not stdin */ 593 if (strcmp(fname, "-") != 0) 594 fclose(fp); 595 596 ret |= fw_env_close(); 597 598 return ret; 599 600 } 601 602 /* 603 * Test for bad block on NAND, just returns 0 on NOR, on NAND: 604 * 0 - block is good 605 * > 0 - block is bad 606 * < 0 - failed to test 607 */ 608 static int flash_bad_block (int fd, uint8_t mtd_type, loff_t *blockstart) 609 { 610 if (mtd_type == MTD_NANDFLASH) { 611 int badblock = ioctl (fd, MEMGETBADBLOCK, blockstart); 612 613 if (badblock < 0) { 614 perror ("Cannot read bad block mark"); 615 return badblock; 616 } 617 618 if (badblock) { 619 #ifdef DEBUG 620 fprintf (stderr, "Bad block at 0x%llx, " 621 "skipping\n", *blockstart); 622 #endif 623 return badblock; 624 } 625 } 626 627 return 0; 628 } 629 630 /* 631 * Read data from flash at an offset into a provided buffer. On NAND it skips 632 * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from 633 * the DEVOFFSET (dev) block. On NOR the loop is only run once. 634 */ 635 static int flash_read_buf (int dev, int fd, void *buf, size_t count, 636 off_t offset, uint8_t mtd_type) 637 { 638 size_t blocklen; /* erase / write length - one block on NAND, 639 0 on NOR */ 640 size_t processed = 0; /* progress counter */ 641 size_t readlen = count; /* current read length */ 642 off_t top_of_range; /* end of the last block we may use */ 643 off_t block_seek; /* offset inside the current block to the start 644 of the data */ 645 loff_t blockstart; /* running start of the current block - 646 MEMGETBADBLOCK needs 64 bits */ 647 int rc; 648 649 blockstart = (offset / DEVESIZE (dev)) * DEVESIZE (dev); 650 651 /* Offset inside a block */ 652 block_seek = offset - blockstart; 653 654 if (mtd_type == MTD_NANDFLASH) { 655 /* 656 * NAND: calculate which blocks we are reading. We have 657 * to read one block at a time to skip bad blocks. 658 */ 659 blocklen = DEVESIZE (dev); 660 661 /* 662 * To calculate the top of the range, we have to use the 663 * global DEVOFFSET (dev), which can be different from offset 664 */ 665 top_of_range = ((DEVOFFSET(dev) / blocklen) + 666 ENVSECTORS (dev)) * blocklen; 667 668 /* Limit to one block for the first read */ 669 if (readlen > blocklen - block_seek) 670 readlen = blocklen - block_seek; 671 } else { 672 blocklen = 0; 673 top_of_range = offset + count; 674 } 675 676 /* This only runs once on NOR flash */ 677 while (processed < count) { 678 rc = flash_bad_block (fd, mtd_type, &blockstart); 679 if (rc < 0) /* block test failed */ 680 return -1; 681 682 if (blockstart + block_seek + readlen > top_of_range) { 683 /* End of range is reached */ 684 fprintf (stderr, 685 "Too few good blocks within range\n"); 686 return -1; 687 } 688 689 if (rc) { /* block is bad */ 690 blockstart += blocklen; 691 continue; 692 } 693 694 /* 695 * If a block is bad, we retry in the next block at the same 696 * offset - see common/env_nand.c::writeenv() 697 */ 698 lseek (fd, blockstart + block_seek, SEEK_SET); 699 700 rc = read (fd, buf + processed, readlen); 701 if (rc != readlen) { 702 fprintf (stderr, "Read error on %s: %s\n", 703 DEVNAME (dev), strerror (errno)); 704 return -1; 705 } 706 #ifdef DEBUG 707 fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n", 708 rc, blockstart + block_seek, DEVNAME(dev)); 709 #endif 710 processed += readlen; 711 readlen = min (blocklen, count - processed); 712 block_seek = 0; 713 blockstart += blocklen; 714 } 715 716 return processed; 717 } 718 719 /* 720 * Write count bytes at offset, but stay within ENVSECTORS (dev) sectors of 721 * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we 722 * erase and write the whole data at once. 723 */ 724 static int flash_write_buf (int dev, int fd, void *buf, size_t count, 725 off_t offset, uint8_t mtd_type) 726 { 727 void *data; 728 struct erase_info_user erase; 729 size_t blocklen; /* length of NAND block / NOR erase sector */ 730 size_t erase_len; /* whole area that can be erased - may include 731 bad blocks */ 732 size_t erasesize; /* erase / write length - one block on NAND, 733 whole area on NOR */ 734 size_t processed = 0; /* progress counter */ 735 size_t write_total; /* total size to actually write - excluding 736 bad blocks */ 737 off_t erase_offset; /* offset to the first erase block (aligned) 738 below offset */ 739 off_t block_seek; /* offset inside the erase block to the start 740 of the data */ 741 off_t top_of_range; /* end of the last block we may use */ 742 loff_t blockstart; /* running start of the current block - 743 MEMGETBADBLOCK needs 64 bits */ 744 int rc; 745 746 blocklen = DEVESIZE (dev); 747 748 top_of_range = ((DEVOFFSET(dev) / blocklen) + 749 ENVSECTORS (dev)) * blocklen; 750 751 erase_offset = (offset / blocklen) * blocklen; 752 753 /* Maximum area we may use */ 754 erase_len = top_of_range - erase_offset; 755 756 blockstart = erase_offset; 757 /* Offset inside a block */ 758 block_seek = offset - erase_offset; 759 760 /* 761 * Data size we actually have to write: from the start of the block 762 * to the start of the data, then count bytes of data, and to the 763 * end of the block 764 */ 765 write_total = ((block_seek + count + blocklen - 1) / 766 blocklen) * blocklen; 767 768 /* 769 * Support data anywhere within erase sectors: read out the complete 770 * area to be erased, replace the environment image, write the whole 771 * block back again. 772 */ 773 if (write_total > count) { 774 data = malloc (erase_len); 775 if (!data) { 776 fprintf (stderr, 777 "Cannot malloc %zu bytes: %s\n", 778 erase_len, strerror (errno)); 779 return -1; 780 } 781 782 rc = flash_read_buf (dev, fd, data, write_total, erase_offset, 783 mtd_type); 784 if (write_total != rc) 785 return -1; 786 787 #ifdef DEBUG 788 fprintf(stderr, "Preserving data "); 789 if (block_seek != 0) 790 fprintf(stderr, "0x%x - 0x%lx", 0, block_seek - 1); 791 if (block_seek + count != write_total) { 792 if (block_seek != 0) 793 fprintf(stderr, " and "); 794 fprintf(stderr, "0x%lx - 0x%x", 795 block_seek + count, write_total - 1); 796 } 797 fprintf(stderr, "\n"); 798 #endif 799 /* Overwrite the old environment */ 800 memcpy (data + block_seek, buf, count); 801 } else { 802 /* 803 * We get here, iff offset is block-aligned and count is a 804 * multiple of blocklen - see write_total calculation above 805 */ 806 data = buf; 807 } 808 809 if (mtd_type == MTD_NANDFLASH) { 810 /* 811 * NAND: calculate which blocks we are writing. We have 812 * to write one block at a time to skip bad blocks. 813 */ 814 erasesize = blocklen; 815 } else { 816 erasesize = erase_len; 817 } 818 819 erase.length = erasesize; 820 821 /* This only runs once on NOR flash and SPI-dataflash */ 822 while (processed < write_total) { 823 rc = flash_bad_block (fd, mtd_type, &blockstart); 824 if (rc < 0) /* block test failed */ 825 return rc; 826 827 if (blockstart + erasesize > top_of_range) { 828 fprintf (stderr, "End of range reached, aborting\n"); 829 return -1; 830 } 831 832 if (rc) { /* block is bad */ 833 blockstart += blocklen; 834 continue; 835 } 836 837 erase.start = blockstart; 838 ioctl (fd, MEMUNLOCK, &erase); 839 840 /* Dataflash does not need an explicit erase cycle */ 841 if (mtd_type != MTD_DATAFLASH) 842 if (ioctl (fd, MEMERASE, &erase) != 0) { 843 fprintf (stderr, "MTD erase error on %s: %s\n", 844 DEVNAME (dev), 845 strerror (errno)); 846 return -1; 847 } 848 849 if (lseek (fd, blockstart, SEEK_SET) == -1) { 850 fprintf (stderr, 851 "Seek error on %s: %s\n", 852 DEVNAME (dev), strerror (errno)); 853 return -1; 854 } 855 856 #ifdef DEBUG 857 fprintf(stderr, "Write 0x%x bytes at 0x%llx\n", erasesize, 858 blockstart); 859 #endif 860 if (write (fd, data + processed, erasesize) != erasesize) { 861 fprintf (stderr, "Write error on %s: %s\n", 862 DEVNAME (dev), strerror (errno)); 863 return -1; 864 } 865 866 ioctl (fd, MEMLOCK, &erase); 867 868 processed += blocklen; 869 block_seek = 0; 870 blockstart += blocklen; 871 } 872 873 if (write_total > count) 874 free (data); 875 876 return processed; 877 } 878 879 /* 880 * Set obsolete flag at offset - NOR flash only 881 */ 882 static int flash_flag_obsolete (int dev, int fd, off_t offset) 883 { 884 int rc; 885 struct erase_info_user erase; 886 887 erase.start = DEVOFFSET (dev); 888 erase.length = DEVESIZE (dev); 889 /* This relies on the fact, that obsolete_flag == 0 */ 890 rc = lseek (fd, offset, SEEK_SET); 891 if (rc < 0) { 892 fprintf (stderr, "Cannot seek to set the flag on %s \n", 893 DEVNAME (dev)); 894 return rc; 895 } 896 ioctl (fd, MEMUNLOCK, &erase); 897 rc = write (fd, &obsolete_flag, sizeof (obsolete_flag)); 898 ioctl (fd, MEMLOCK, &erase); 899 if (rc < 0) 900 perror ("Could not set obsolete flag"); 901 902 return rc; 903 } 904 905 static int flash_write (int fd_current, int fd_target, int dev_target) 906 { 907 int rc; 908 909 switch (environment.flag_scheme) { 910 case FLAG_NONE: 911 break; 912 case FLAG_INCREMENTAL: 913 (*environment.flags)++; 914 break; 915 case FLAG_BOOLEAN: 916 *environment.flags = active_flag; 917 break; 918 default: 919 fprintf (stderr, "Unimplemented flash scheme %u \n", 920 environment.flag_scheme); 921 return -1; 922 } 923 924 #ifdef DEBUG 925 fprintf(stderr, "Writing new environment at 0x%lx on %s\n", 926 DEVOFFSET (dev_target), DEVNAME (dev_target)); 927 #endif 928 rc = flash_write_buf(dev_target, fd_target, environment.image, 929 CUR_ENVSIZE, DEVOFFSET(dev_target), 930 DEVTYPE(dev_target)); 931 if (rc < 0) 932 return rc; 933 934 if (environment.flag_scheme == FLAG_BOOLEAN) { 935 /* Have to set obsolete flag */ 936 off_t offset = DEVOFFSET (dev_current) + 937 offsetof (struct env_image_redundant, flags); 938 #ifdef DEBUG 939 fprintf(stderr, 940 "Setting obsolete flag in environment at 0x%lx on %s\n", 941 DEVOFFSET (dev_current), DEVNAME (dev_current)); 942 #endif 943 flash_flag_obsolete (dev_current, fd_current, offset); 944 } 945 946 return 0; 947 } 948 949 static int flash_read (int fd) 950 { 951 struct mtd_info_user mtdinfo; 952 int rc; 953 954 rc = ioctl (fd, MEMGETINFO, &mtdinfo); 955 if (rc < 0) { 956 perror ("Cannot get MTD information"); 957 return -1; 958 } 959 960 if (mtdinfo.type != MTD_NORFLASH && 961 mtdinfo.type != MTD_NANDFLASH && 962 mtdinfo.type != MTD_DATAFLASH) { 963 fprintf (stderr, "Unsupported flash type %u\n", mtdinfo.type); 964 return -1; 965 } 966 967 DEVTYPE(dev_current) = mtdinfo.type; 968 969 rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE, 970 DEVOFFSET (dev_current), mtdinfo.type); 971 972 return (rc != CUR_ENVSIZE) ? -1 : 0; 973 } 974 975 static int flash_io (int mode) 976 { 977 int fd_current, fd_target, rc, dev_target; 978 979 /* dev_current: fd_current, erase_current */ 980 fd_current = open (DEVNAME (dev_current), mode); 981 if (fd_current < 0) { 982 fprintf (stderr, 983 "Can't open %s: %s\n", 984 DEVNAME (dev_current), strerror (errno)); 985 return -1; 986 } 987 988 if (mode == O_RDWR) { 989 if (HaveRedundEnv) { 990 /* switch to next partition for writing */ 991 dev_target = !dev_current; 992 /* dev_target: fd_target, erase_target */ 993 fd_target = open (DEVNAME (dev_target), mode); 994 if (fd_target < 0) { 995 fprintf (stderr, 996 "Can't open %s: %s\n", 997 DEVNAME (dev_target), 998 strerror (errno)); 999 rc = -1; 1000 goto exit; 1001 } 1002 } else { 1003 dev_target = dev_current; 1004 fd_target = fd_current; 1005 } 1006 1007 rc = flash_write (fd_current, fd_target, dev_target); 1008 1009 if (HaveRedundEnv) { 1010 if (close (fd_target)) { 1011 fprintf (stderr, 1012 "I/O error on %s: %s\n", 1013 DEVNAME (dev_target), 1014 strerror (errno)); 1015 rc = -1; 1016 } 1017 } 1018 } else { 1019 rc = flash_read (fd_current); 1020 } 1021 1022 exit: 1023 if (close (fd_current)) { 1024 fprintf (stderr, 1025 "I/O error on %s: %s\n", 1026 DEVNAME (dev_current), strerror (errno)); 1027 return -1; 1028 } 1029 1030 return rc; 1031 } 1032 1033 /* 1034 * s1 is either a simple 'name', or a 'name=value' pair. 1035 * s2 is a 'name=value' pair. 1036 * If the names match, return the value of s2, else NULL. 1037 */ 1038 1039 static char *envmatch (char * s1, char * s2) 1040 { 1041 if (s1 == NULL || s2 == NULL) 1042 return NULL; 1043 1044 while (*s1 == *s2++) 1045 if (*s1++ == '=') 1046 return s2; 1047 if (*s1 == '\0' && *(s2 - 1) == '=') 1048 return s2; 1049 return NULL; 1050 } 1051 1052 /* 1053 * Prevent confusion if running from erased flash memory 1054 */ 1055 int fw_env_open(void) 1056 { 1057 int crc0, crc0_ok; 1058 unsigned char flag0; 1059 void *addr0; 1060 1061 int crc1, crc1_ok; 1062 unsigned char flag1; 1063 void *addr1; 1064 1065 struct env_image_single *single; 1066 struct env_image_redundant *redundant; 1067 1068 if (parse_config ()) /* should fill envdevices */ 1069 return -1; 1070 1071 addr0 = calloc(1, CUR_ENVSIZE); 1072 if (addr0 == NULL) { 1073 fprintf(stderr, 1074 "Not enough memory for environment (%ld bytes)\n", 1075 CUR_ENVSIZE); 1076 return -1; 1077 } 1078 1079 /* read environment from FLASH to local buffer */ 1080 environment.image = addr0; 1081 1082 if (HaveRedundEnv) { 1083 redundant = addr0; 1084 environment.crc = &redundant->crc; 1085 environment.flags = &redundant->flags; 1086 environment.data = redundant->data; 1087 } else { 1088 single = addr0; 1089 environment.crc = &single->crc; 1090 environment.flags = NULL; 1091 environment.data = single->data; 1092 } 1093 1094 dev_current = 0; 1095 if (flash_io (O_RDONLY)) 1096 return -1; 1097 1098 crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE); 1099 crc0_ok = (crc0 == *environment.crc); 1100 if (!HaveRedundEnv) { 1101 if (!crc0_ok) { 1102 fprintf (stderr, 1103 "Warning: Bad CRC, using default environment\n"); 1104 memcpy(environment.data, default_environment, sizeof default_environment); 1105 } 1106 } else { 1107 flag0 = *environment.flags; 1108 1109 dev_current = 1; 1110 addr1 = calloc(1, CUR_ENVSIZE); 1111 if (addr1 == NULL) { 1112 fprintf(stderr, 1113 "Not enough memory for environment (%ld bytes)\n", 1114 CUR_ENVSIZE); 1115 return -1; 1116 } 1117 redundant = addr1; 1118 1119 /* 1120 * have to set environment.image for flash_read(), careful - 1121 * other pointers in environment still point inside addr0 1122 */ 1123 environment.image = addr1; 1124 if (flash_io (O_RDONLY)) 1125 return -1; 1126 1127 /* Check flag scheme compatibility */ 1128 if (DEVTYPE(dev_current) == MTD_NORFLASH && 1129 DEVTYPE(!dev_current) == MTD_NORFLASH) { 1130 environment.flag_scheme = FLAG_BOOLEAN; 1131 } else if (DEVTYPE(dev_current) == MTD_NANDFLASH && 1132 DEVTYPE(!dev_current) == MTD_NANDFLASH) { 1133 environment.flag_scheme = FLAG_INCREMENTAL; 1134 } else if (DEVTYPE(dev_current) == MTD_DATAFLASH && 1135 DEVTYPE(!dev_current) == MTD_DATAFLASH) { 1136 environment.flag_scheme = FLAG_BOOLEAN; 1137 } else { 1138 fprintf (stderr, "Incompatible flash types!\n"); 1139 return -1; 1140 } 1141 1142 crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE); 1143 crc1_ok = (crc1 == redundant->crc); 1144 flag1 = redundant->flags; 1145 1146 if (crc0_ok && !crc1_ok) { 1147 dev_current = 0; 1148 } else if (!crc0_ok && crc1_ok) { 1149 dev_current = 1; 1150 } else if (!crc0_ok && !crc1_ok) { 1151 fprintf (stderr, 1152 "Warning: Bad CRC, using default environment\n"); 1153 memcpy (environment.data, default_environment, 1154 sizeof default_environment); 1155 dev_current = 0; 1156 } else { 1157 switch (environment.flag_scheme) { 1158 case FLAG_BOOLEAN: 1159 if (flag0 == active_flag && 1160 flag1 == obsolete_flag) { 1161 dev_current = 0; 1162 } else if (flag0 == obsolete_flag && 1163 flag1 == active_flag) { 1164 dev_current = 1; 1165 } else if (flag0 == flag1) { 1166 dev_current = 0; 1167 } else if (flag0 == 0xFF) { 1168 dev_current = 0; 1169 } else if (flag1 == 0xFF) { 1170 dev_current = 1; 1171 } else { 1172 dev_current = 0; 1173 } 1174 break; 1175 case FLAG_INCREMENTAL: 1176 if (flag0 == 255 && flag1 == 0) 1177 dev_current = 1; 1178 else if ((flag1 == 255 && flag0 == 0) || 1179 flag0 >= flag1) 1180 dev_current = 0; 1181 else /* flag1 > flag0 */ 1182 dev_current = 1; 1183 break; 1184 default: 1185 fprintf (stderr, "Unknown flag scheme %u \n", 1186 environment.flag_scheme); 1187 return -1; 1188 } 1189 } 1190 1191 /* 1192 * If we are reading, we don't need the flag and the CRC any 1193 * more, if we are writing, we will re-calculate CRC and update 1194 * flags before writing out 1195 */ 1196 if (dev_current) { 1197 environment.image = addr1; 1198 environment.crc = &redundant->crc; 1199 environment.flags = &redundant->flags; 1200 environment.data = redundant->data; 1201 free (addr0); 1202 } else { 1203 environment.image = addr0; 1204 /* Other pointers are already set */ 1205 free (addr1); 1206 } 1207 #ifdef DEBUG 1208 fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current)); 1209 #endif 1210 } 1211 return 0; 1212 } 1213 1214 1215 static int parse_config () 1216 { 1217 struct stat st; 1218 1219 #if defined(CONFIG_FILE) 1220 /* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */ 1221 if (get_config (CONFIG_FILE)) { 1222 fprintf (stderr, 1223 "Cannot parse config file: %s\n", strerror (errno)); 1224 return -1; 1225 } 1226 #else 1227 strcpy (DEVNAME (0), DEVICE1_NAME); 1228 DEVOFFSET (0) = DEVICE1_OFFSET; 1229 ENVSIZE (0) = ENV1_SIZE; 1230 /* Default values are: erase-size=env-size, #sectors=1 */ 1231 DEVESIZE (0) = ENVSIZE (0); 1232 ENVSECTORS (0) = 1; 1233 #ifdef DEVICE1_ESIZE 1234 DEVESIZE (0) = DEVICE1_ESIZE; 1235 #endif 1236 #ifdef DEVICE1_ENVSECTORS 1237 ENVSECTORS (0) = DEVICE1_ENVSECTORS; 1238 #endif 1239 1240 #ifdef HAVE_REDUND 1241 strcpy (DEVNAME (1), DEVICE2_NAME); 1242 DEVOFFSET (1) = DEVICE2_OFFSET; 1243 ENVSIZE (1) = ENV2_SIZE; 1244 /* Default values are: erase-size=env-size, #sectors=1 */ 1245 DEVESIZE (1) = ENVSIZE (1); 1246 ENVSECTORS (1) = 1; 1247 #ifdef DEVICE2_ESIZE 1248 DEVESIZE (1) = DEVICE2_ESIZE; 1249 #endif 1250 #ifdef DEVICE2_ENVSECTORS 1251 ENVSECTORS (1) = DEVICE2_ENVSECTORS; 1252 #endif 1253 HaveRedundEnv = 1; 1254 #endif 1255 #endif 1256 if (stat (DEVNAME (0), &st)) { 1257 fprintf (stderr, 1258 "Cannot access MTD device %s: %s\n", 1259 DEVNAME (0), strerror (errno)); 1260 return -1; 1261 } 1262 1263 if (HaveRedundEnv && stat (DEVNAME (1), &st)) { 1264 fprintf (stderr, 1265 "Cannot access MTD device %s: %s\n", 1266 DEVNAME (1), strerror (errno)); 1267 return -1; 1268 } 1269 return 0; 1270 } 1271 1272 #if defined(CONFIG_FILE) 1273 static int get_config (char *fname) 1274 { 1275 FILE *fp; 1276 int i = 0; 1277 int rc; 1278 char dump[128]; 1279 1280 fp = fopen (fname, "r"); 1281 if (fp == NULL) 1282 return -1; 1283 1284 while (i < 2 && fgets (dump, sizeof (dump), fp)) { 1285 /* Skip incomplete conversions and comment strings */ 1286 if (dump[0] == '#') 1287 continue; 1288 1289 rc = sscanf (dump, "%s %lx %lx %lx %lx", 1290 DEVNAME (i), 1291 &DEVOFFSET (i), 1292 &ENVSIZE (i), 1293 &DEVESIZE (i), 1294 &ENVSECTORS (i)); 1295 1296 if (rc < 3) 1297 continue; 1298 1299 if (rc < 4) 1300 /* Assume the erase size is the same as the env-size */ 1301 DEVESIZE(i) = ENVSIZE(i); 1302 1303 if (rc < 5) 1304 /* Default - 1 sector */ 1305 ENVSECTORS (i) = 1; 1306 1307 i++; 1308 } 1309 fclose (fp); 1310 1311 HaveRedundEnv = i - 1; 1312 if (!i) { /* No valid entries found */ 1313 errno = EINVAL; 1314 return -1; 1315 } else 1316 return 0; 1317 } 1318 #endif 1319