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