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 <linux/stringify.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <stddef.h> 33 #include <string.h> 34 #include <sys/types.h> 35 #include <sys/ioctl.h> 36 #include <sys/stat.h> 37 #include <unistd.h> 38 39 #ifdef MTD_OLD 40 # include <stdint.h> 41 # include <linux/mtd/mtd.h> 42 #else 43 # define __user /* nothing */ 44 # include <mtd/mtd-user.h> 45 #endif 46 47 #include "fw_env.h" 48 49 #define WHITESPACE(c) ((c == '\t') || (c == ' ')) 50 51 #define min(x, y) ({ \ 52 typeof(x) _min1 = (x); \ 53 typeof(y) _min2 = (y); \ 54 (void) (&_min1 == &_min2); \ 55 _min1 < _min2 ? _min1 : _min2; }) 56 57 struct envdev_s { 58 char devname[16]; /* Device name */ 59 ulong devoff; /* Device offset */ 60 ulong env_size; /* environment size */ 61 ulong erase_size; /* device erase size */ 62 ulong env_sectors; /* number of environment sectors */ 63 uint8_t mtd_type; /* type of the MTD device */ 64 }; 65 66 static struct envdev_s envdevices[2] = 67 { 68 { 69 .mtd_type = MTD_ABSENT, 70 }, { 71 .mtd_type = MTD_ABSENT, 72 }, 73 }; 74 static int dev_current; 75 76 #define DEVNAME(i) envdevices[(i)].devname 77 #define DEVOFFSET(i) envdevices[(i)].devoff 78 #define ENVSIZE(i) envdevices[(i)].env_size 79 #define DEVESIZE(i) envdevices[(i)].erase_size 80 #define ENVSECTORS(i) envdevices[(i)].env_sectors 81 #define DEVTYPE(i) envdevices[(i)].mtd_type 82 83 #define CUR_ENVSIZE ENVSIZE(dev_current) 84 85 #define ENV_SIZE getenvsize() 86 87 struct env_image_single { 88 uint32_t crc; /* CRC32 over data bytes */ 89 char data[]; 90 }; 91 92 struct env_image_redundant { 93 uint32_t crc; /* CRC32 over data bytes */ 94 unsigned char flags; /* active or obsolete */ 95 char data[]; 96 }; 97 98 enum flag_scheme { 99 FLAG_NONE, 100 FLAG_BOOLEAN, 101 FLAG_INCREMENTAL, 102 }; 103 104 struct environment { 105 void *image; 106 uint32_t *crc; 107 unsigned char *flags; 108 char *data; 109 enum flag_scheme flag_scheme; 110 }; 111 112 static struct environment environment = { 113 .flag_scheme = FLAG_NONE, 114 }; 115 116 static int HaveRedundEnv = 0; 117 118 static unsigned char active_flag = 1; 119 /* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */ 120 static unsigned char obsolete_flag = 0; 121 122 123 static char default_environment[] = { 124 #if defined(CONFIG_BOOTARGS) 125 "bootargs=" CONFIG_BOOTARGS "\0" 126 #endif 127 #if defined(CONFIG_BOOTCOMMAND) 128 "bootcmd=" CONFIG_BOOTCOMMAND "\0" 129 #endif 130 #if defined(CONFIG_RAMBOOTCOMMAND) 131 "ramboot=" CONFIG_RAMBOOTCOMMAND "\0" 132 #endif 133 #if defined(CONFIG_NFSBOOTCOMMAND) 134 "nfsboot=" CONFIG_NFSBOOTCOMMAND "\0" 135 #endif 136 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 137 "bootdelay=" __stringify(CONFIG_BOOTDELAY) "\0" 138 #endif 139 #if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0) 140 "baudrate=" __stringify(CONFIG_BAUDRATE) "\0" 141 #endif 142 #ifdef CONFIG_LOADS_ECHO 143 "loads_echo=" __stringify(CONFIG_LOADS_ECHO) "\0" 144 #endif 145 #ifdef CONFIG_ETHADDR 146 "ethaddr=" __stringify(CONFIG_ETHADDR) "\0" 147 #endif 148 #ifdef CONFIG_ETH1ADDR 149 "eth1addr=" __stringify(CONFIG_ETH1ADDR) "\0" 150 #endif 151 #ifdef CONFIG_ETH2ADDR 152 "eth2addr=" __stringify(CONFIG_ETH2ADDR) "\0" 153 #endif 154 #ifdef CONFIG_ETH3ADDR 155 "eth3addr=" __stringify(CONFIG_ETH3ADDR) "\0" 156 #endif 157 #ifdef CONFIG_ETH4ADDR 158 "eth4addr=" __stringify(CONFIG_ETH4ADDR) "\0" 159 #endif 160 #ifdef CONFIG_ETH5ADDR 161 "eth5addr=" __stringify(CONFIG_ETH5ADDR) "\0" 162 #endif 163 #ifdef CONFIG_ETHPRIME 164 "ethprime=" CONFIG_ETHPRIME "\0" 165 #endif 166 #ifdef CONFIG_IPADDR 167 "ipaddr=" __stringify(CONFIG_IPADDR) "\0" 168 #endif 169 #ifdef CONFIG_SERVERIP 170 "serverip=" __stringify(CONFIG_SERVERIP) "\0" 171 #endif 172 #ifdef CONFIG_SYS_AUTOLOAD 173 "autoload=" CONFIG_SYS_AUTOLOAD "\0" 174 #endif 175 #ifdef CONFIG_ROOTPATH 176 "rootpath=" CONFIG_ROOTPATH "\0" 177 #endif 178 #ifdef CONFIG_GATEWAYIP 179 "gatewayip=" __stringify(CONFIG_GATEWAYIP) "\0" 180 #endif 181 #ifdef CONFIG_NETMASK 182 "netmask=" __stringify(CONFIG_NETMASK) "\0" 183 #endif 184 #ifdef CONFIG_HOSTNAME 185 "hostname=" __stringify(CONFIG_HOSTNAME) "\0" 186 #endif 187 #ifdef CONFIG_BOOTFILE 188 "bootfile=" CONFIG_BOOTFILE "\0" 189 #endif 190 #ifdef CONFIG_LOADADDR 191 "loadaddr=" __stringify(CONFIG_LOADADDR) "\0" 192 #endif 193 #ifdef CONFIG_PREBOOT 194 "preboot=" CONFIG_PREBOOT "\0" 195 #endif 196 #ifdef CONFIG_CLOCKS_IN_MHZ 197 "clocks_in_mhz=" "1" "\0" 198 #endif 199 #if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0) 200 "pcidelay=" __stringify(CONFIG_PCI_BOOTDELAY) "\0" 201 #endif 202 #ifdef CONFIG_ENV_VARS_UBOOT_CONFIG 203 "arch=" CONFIG_SYS_ARCH "\0" 204 "cpu=" CONFIG_SYS_CPU "\0" 205 "board=" CONFIG_SYS_BOARD "\0" 206 #ifdef CONFIG_SYS_VENDOR 207 "vendor=" CONFIG_SYS_VENDOR "\0" 208 #endif 209 #ifdef CONFIG_SYS_SOC 210 "soc=" CONFIG_SYS_SOC "\0" 211 #endif 212 #endif 213 #ifdef CONFIG_EXTRA_ENV_SETTINGS 214 CONFIG_EXTRA_ENV_SETTINGS 215 #endif 216 "\0" /* Termimate struct environment data with 2 NULs */ 217 }; 218 219 static int flash_io (int mode); 220 static char *envmatch (char * s1, char * s2); 221 static int parse_config (void); 222 223 #if defined(CONFIG_FILE) 224 static int get_config (char *); 225 #endif 226 static inline ulong getenvsize (void) 227 { 228 ulong rc = CUR_ENVSIZE - sizeof(long); 229 230 if (HaveRedundEnv) 231 rc -= sizeof (char); 232 return rc; 233 } 234 235 static char *fw_string_blank(char *s, int noblank) 236 { 237 int i; 238 int len = strlen(s); 239 240 for (i = 0; i < len; i++, s++) { 241 if ((noblank && !WHITESPACE(*s)) || 242 (!noblank && WHITESPACE(*s))) 243 break; 244 } 245 if (i == len) 246 return NULL; 247 248 return s; 249 } 250 251 /* 252 * Search the environment for a variable. 253 * Return the value, if found, or NULL, if not found. 254 */ 255 char *fw_getenv (char *name) 256 { 257 char *env, *nxt; 258 259 for (env = environment.data; *env; env = nxt + 1) { 260 char *val; 261 262 for (nxt = env; *nxt; ++nxt) { 263 if (nxt >= &environment.data[ENV_SIZE]) { 264 fprintf (stderr, "## Error: " 265 "environment not terminated\n"); 266 return NULL; 267 } 268 } 269 val = envmatch (name, env); 270 if (!val) 271 continue; 272 return val; 273 } 274 return NULL; 275 } 276 277 /* 278 * Print the current definition of one, or more, or all 279 * environment variables 280 */ 281 int fw_printenv (int argc, char *argv[]) 282 { 283 char *env, *nxt; 284 int i, n_flag; 285 int rc = 0; 286 287 if (fw_env_open()) 288 return -1; 289 290 if (argc == 1) { /* Print all env variables */ 291 for (env = environment.data; *env; env = nxt + 1) { 292 for (nxt = env; *nxt; ++nxt) { 293 if (nxt >= &environment.data[ENV_SIZE]) { 294 fprintf (stderr, "## Error: " 295 "environment not terminated\n"); 296 return -1; 297 } 298 } 299 300 printf ("%s\n", env); 301 } 302 return 0; 303 } 304 305 if (strcmp (argv[1], "-n") == 0) { 306 n_flag = 1; 307 ++argv; 308 --argc; 309 if (argc != 2) { 310 fprintf (stderr, "## Error: " 311 "`-n' option requires exactly one argument\n"); 312 return -1; 313 } 314 } else { 315 n_flag = 0; 316 } 317 318 for (i = 1; i < argc; ++i) { /* print single env variables */ 319 char *name = argv[i]; 320 char *val = NULL; 321 322 for (env = environment.data; *env; env = nxt + 1) { 323 324 for (nxt = env; *nxt; ++nxt) { 325 if (nxt >= &environment.data[ENV_SIZE]) { 326 fprintf (stderr, "## Error: " 327 "environment not terminated\n"); 328 return -1; 329 } 330 } 331 val = envmatch (name, env); 332 if (val) { 333 if (!n_flag) { 334 fputs (name, stdout); 335 putc ('=', stdout); 336 } 337 puts (val); 338 break; 339 } 340 } 341 if (!val) { 342 fprintf (stderr, "## Error: \"%s\" not defined\n", name); 343 rc = -1; 344 } 345 } 346 347 return rc; 348 } 349 350 int fw_env_close(void) 351 { 352 /* 353 * Update CRC 354 */ 355 *environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE); 356 357 /* write environment back to flash */ 358 if (flash_io(O_RDWR)) { 359 fprintf(stderr, 360 "Error: can't write fw_env to flash\n"); 361 return -1; 362 } 363 364 return 0; 365 } 366 367 368 /* 369 * Set/Clear a single variable in the environment. 370 * This is called in sequence to update the environment 371 * in RAM without updating the copy in flash after each set 372 */ 373 int fw_env_write(char *name, char *value) 374 { 375 int len; 376 char *env, *nxt; 377 char *oldval = NULL; 378 379 /* 380 * search if variable with this name already exists 381 */ 382 for (nxt = env = environment.data; *env; env = nxt + 1) { 383 for (nxt = env; *nxt; ++nxt) { 384 if (nxt >= &environment.data[ENV_SIZE]) { 385 fprintf(stderr, "## Error: " 386 "environment not terminated\n"); 387 errno = EINVAL; 388 return -1; 389 } 390 } 391 if ((oldval = envmatch (name, env)) != NULL) 392 break; 393 } 394 395 /* 396 * Delete any existing definition 397 */ 398 if (oldval) { 399 #ifndef CONFIG_ENV_OVERWRITE 400 /* 401 * Ethernet Address and serial# can be set only once 402 */ 403 if ( 404 (strcmp(name, "serial#") == 0) || 405 ((strcmp(name, "ethaddr") == 0) 406 #if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) 407 && (strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0) 408 #endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */ 409 ) ) { 410 fprintf (stderr, "Can't overwrite \"%s\"\n", name); 411 errno = EROFS; 412 return -1; 413 } 414 #endif /* CONFIG_ENV_OVERWRITE */ 415 416 if (*++nxt == '\0') { 417 *env = '\0'; 418 } else { 419 for (;;) { 420 *env = *nxt++; 421 if ((*env == '\0') && (*nxt == '\0')) 422 break; 423 ++env; 424 } 425 } 426 *++env = '\0'; 427 } 428 429 /* Delete only ? */ 430 if (!value || !strlen(value)) 431 return 0; 432 433 /* 434 * Append new definition at the end 435 */ 436 for (env = environment.data; *env || *(env + 1); ++env); 437 if (env > environment.data) 438 ++env; 439 /* 440 * Overflow when: 441 * "name" + "=" + "val" +"\0\0" > CUR_ENVSIZE - (env-environment) 442 */ 443 len = strlen (name) + 2; 444 /* add '=' for first arg, ' ' for all others */ 445 len += strlen(value) + 1; 446 447 if (len > (&environment.data[ENV_SIZE] - env)) { 448 fprintf (stderr, 449 "Error: environment overflow, \"%s\" deleted\n", 450 name); 451 return -1; 452 } 453 454 while ((*env = *name++) != '\0') 455 env++; 456 *env = '='; 457 while ((*++env = *value++) != '\0') 458 ; 459 460 /* end is marked with double '\0' */ 461 *++env = '\0'; 462 463 return 0; 464 } 465 466 /* 467 * Deletes or sets environment variables. Returns -1 and sets errno error codes: 468 * 0 - OK 469 * EINVAL - need at least 1 argument 470 * EROFS - certain variables ("ethaddr", "serial#") cannot be 471 * modified or deleted 472 * 473 */ 474 int fw_setenv(int argc, char *argv[]) 475 { 476 int i, len; 477 char *name; 478 char *value = NULL; 479 480 if (argc < 2) { 481 errno = EINVAL; 482 return -1; 483 } 484 485 if (fw_env_open()) { 486 fprintf(stderr, "Error: environment not initialized\n"); 487 return -1; 488 } 489 490 name = argv[1]; 491 492 len = 0; 493 for (i = 2; i < argc; ++i) { 494 char *val = argv[i]; 495 size_t val_len = strlen(val); 496 497 if (value) 498 value[len - 1] = ' '; 499 value = realloc(value, len + val_len + 1); 500 if (!value) { 501 fprintf(stderr, 502 "Cannot malloc %zu bytes: %s\n", 503 len, strerror(errno)); 504 return -1; 505 } 506 507 memcpy(value + len, val, val_len); 508 len += val_len; 509 value[len++] = '\0'; 510 } 511 512 fw_env_write(name, value); 513 514 free(value); 515 516 return fw_env_close(); 517 } 518 519 /* 520 * Parse a file and configure the u-boot variables. 521 * The script file has a very simple format, as follows: 522 * 523 * Each line has a couple with name, value: 524 * <white spaces>variable_name<white spaces>variable_value 525 * 526 * Both variable_name and variable_value are interpreted as strings. 527 * Any character after <white spaces> and before ending \r\n is interpreted 528 * as variable's value (no comment allowed on these lines !) 529 * 530 * Comments are allowed if the first character in the line is # 531 * 532 * Returns -1 and sets errno error codes: 533 * 0 - OK 534 * -1 - Error 535 */ 536 int fw_parse_script(char *fname) 537 { 538 FILE *fp; 539 char dump[1024]; /* Maximum line length in the file */ 540 char *name; 541 char *val; 542 int lineno = 0; 543 int len; 544 int ret = 0; 545 546 if (fw_env_open()) { 547 fprintf(stderr, "Error: environment not initialized\n"); 548 return -1; 549 } 550 551 if (strcmp(fname, "-") == 0) 552 fp = stdin; 553 else { 554 fp = fopen(fname, "r"); 555 if (fp == NULL) { 556 fprintf(stderr, "I cannot open %s for reading\n", 557 fname); 558 return -1; 559 } 560 } 561 562 while (fgets(dump, sizeof(dump), fp)) { 563 lineno++; 564 len = strlen(dump); 565 566 /* 567 * Read a whole line from the file. If the line is too long 568 * or is not terminated, reports an error and exit. 569 */ 570 if (dump[len - 1] != '\n') { 571 fprintf(stderr, 572 "Line %d not corrected terminated or too long\n", 573 lineno); 574 ret = -1; 575 break; 576 } 577 578 /* Drop ending line feed / carriage return */ 579 while (len > 0 && (dump[len - 1] == '\n' || 580 dump[len - 1] == '\r')) { 581 dump[len - 1] = '\0'; 582 len--; 583 } 584 585 /* Skip comment or empty lines */ 586 if ((len == 0) || dump[0] == '#') 587 continue; 588 589 /* 590 * Search for variable's name, 591 * remove leading whitespaces 592 */ 593 name = fw_string_blank(dump, 1); 594 if (!name) 595 continue; 596 597 /* The first white space is the end of variable name */ 598 val = fw_string_blank(name, 0); 599 len = strlen(name); 600 if (val) { 601 *val++ = '\0'; 602 if ((val - name) < len) 603 val = fw_string_blank(val, 1); 604 else 605 val = NULL; 606 } 607 608 #ifdef DEBUG 609 fprintf(stderr, "Setting %s : %s\n", 610 name, val ? val : " removed"); 611 #endif 612 613 /* 614 * If there is an error setting a variable, 615 * try to save the environment and returns an error 616 */ 617 if (fw_env_write(name, val)) { 618 fprintf(stderr, 619 "fw_env_write returns with error : %s\n", 620 strerror(errno)); 621 ret = -1; 622 break; 623 } 624 625 } 626 627 /* Close file if not stdin */ 628 if (strcmp(fname, "-") != 0) 629 fclose(fp); 630 631 ret |= fw_env_close(); 632 633 return ret; 634 635 } 636 637 /* 638 * Test for bad block on NAND, just returns 0 on NOR, on NAND: 639 * 0 - block is good 640 * > 0 - block is bad 641 * < 0 - failed to test 642 */ 643 static int flash_bad_block (int fd, uint8_t mtd_type, loff_t *blockstart) 644 { 645 if (mtd_type == MTD_NANDFLASH) { 646 int badblock = ioctl (fd, MEMGETBADBLOCK, blockstart); 647 648 if (badblock < 0) { 649 perror ("Cannot read bad block mark"); 650 return badblock; 651 } 652 653 if (badblock) { 654 #ifdef DEBUG 655 fprintf (stderr, "Bad block at 0x%llx, " 656 "skipping\n", *blockstart); 657 #endif 658 return badblock; 659 } 660 } 661 662 return 0; 663 } 664 665 /* 666 * Read data from flash at an offset into a provided buffer. On NAND it skips 667 * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from 668 * the DEVOFFSET (dev) block. On NOR the loop is only run once. 669 */ 670 static int flash_read_buf (int dev, int fd, void *buf, size_t count, 671 off_t offset, uint8_t mtd_type) 672 { 673 size_t blocklen; /* erase / write length - one block on NAND, 674 0 on NOR */ 675 size_t processed = 0; /* progress counter */ 676 size_t readlen = count; /* current read length */ 677 off_t top_of_range; /* end of the last block we may use */ 678 off_t block_seek; /* offset inside the current block to the start 679 of the data */ 680 loff_t blockstart; /* running start of the current block - 681 MEMGETBADBLOCK needs 64 bits */ 682 int rc; 683 684 blockstart = (offset / DEVESIZE (dev)) * DEVESIZE (dev); 685 686 /* Offset inside a block */ 687 block_seek = offset - blockstart; 688 689 if (mtd_type == MTD_NANDFLASH) { 690 /* 691 * NAND: calculate which blocks we are reading. We have 692 * to read one block at a time to skip bad blocks. 693 */ 694 blocklen = DEVESIZE (dev); 695 696 /* 697 * To calculate the top of the range, we have to use the 698 * global DEVOFFSET (dev), which can be different from offset 699 */ 700 top_of_range = ((DEVOFFSET(dev) / blocklen) + 701 ENVSECTORS (dev)) * blocklen; 702 703 /* Limit to one block for the first read */ 704 if (readlen > blocklen - block_seek) 705 readlen = blocklen - block_seek; 706 } else { 707 blocklen = 0; 708 top_of_range = offset + count; 709 } 710 711 /* This only runs once on NOR flash */ 712 while (processed < count) { 713 rc = flash_bad_block (fd, mtd_type, &blockstart); 714 if (rc < 0) /* block test failed */ 715 return -1; 716 717 if (blockstart + block_seek + readlen > top_of_range) { 718 /* End of range is reached */ 719 fprintf (stderr, 720 "Too few good blocks within range\n"); 721 return -1; 722 } 723 724 if (rc) { /* block is bad */ 725 blockstart += blocklen; 726 continue; 727 } 728 729 /* 730 * If a block is bad, we retry in the next block at the same 731 * offset - see common/env_nand.c::writeenv() 732 */ 733 lseek (fd, blockstart + block_seek, SEEK_SET); 734 735 rc = read (fd, buf + processed, readlen); 736 if (rc != readlen) { 737 fprintf (stderr, "Read error on %s: %s\n", 738 DEVNAME (dev), strerror (errno)); 739 return -1; 740 } 741 #ifdef DEBUG 742 fprintf (stderr, "Read 0x%x bytes at 0x%llx\n", 743 rc, blockstart + block_seek); 744 #endif 745 processed += readlen; 746 readlen = min (blocklen, count - processed); 747 block_seek = 0; 748 blockstart += blocklen; 749 } 750 751 return processed; 752 } 753 754 /* 755 * Write count bytes at offset, but stay within ENVSECTORS (dev) sectors of 756 * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we 757 * erase and write the whole data at once. 758 */ 759 static int flash_write_buf (int dev, int fd, void *buf, size_t count, 760 off_t offset, uint8_t mtd_type) 761 { 762 void *data; 763 struct erase_info_user erase; 764 size_t blocklen; /* length of NAND block / NOR erase sector */ 765 size_t erase_len; /* whole area that can be erased - may include 766 bad blocks */ 767 size_t erasesize; /* erase / write length - one block on NAND, 768 whole area on NOR */ 769 size_t processed = 0; /* progress counter */ 770 size_t write_total; /* total size to actually write - excluding 771 bad blocks */ 772 off_t erase_offset; /* offset to the first erase block (aligned) 773 below offset */ 774 off_t block_seek; /* offset inside the erase block to the start 775 of the data */ 776 off_t top_of_range; /* end of the last block we may use */ 777 loff_t blockstart; /* running start of the current block - 778 MEMGETBADBLOCK needs 64 bits */ 779 int rc; 780 781 blocklen = DEVESIZE (dev); 782 783 top_of_range = ((DEVOFFSET(dev) / blocklen) + 784 ENVSECTORS (dev)) * blocklen; 785 786 erase_offset = (offset / blocklen) * blocklen; 787 788 /* Maximum area we may use */ 789 erase_len = top_of_range - erase_offset; 790 791 blockstart = erase_offset; 792 /* Offset inside a block */ 793 block_seek = offset - erase_offset; 794 795 /* 796 * Data size we actually have to write: from the start of the block 797 * to the start of the data, then count bytes of data, and to the 798 * end of the block 799 */ 800 write_total = ((block_seek + count + blocklen - 1) / 801 blocklen) * blocklen; 802 803 /* 804 * Support data anywhere within erase sectors: read out the complete 805 * area to be erased, replace the environment image, write the whole 806 * block back again. 807 */ 808 if (write_total > count) { 809 data = malloc (erase_len); 810 if (!data) { 811 fprintf (stderr, 812 "Cannot malloc %zu bytes: %s\n", 813 erase_len, strerror (errno)); 814 return -1; 815 } 816 817 rc = flash_read_buf (dev, fd, data, write_total, erase_offset, 818 mtd_type); 819 if (write_total != rc) 820 return -1; 821 822 /* Overwrite the old environment */ 823 memcpy (data + block_seek, buf, count); 824 } else { 825 /* 826 * We get here, iff offset is block-aligned and count is a 827 * multiple of blocklen - see write_total calculation above 828 */ 829 data = buf; 830 } 831 832 if (mtd_type == MTD_NANDFLASH) { 833 /* 834 * NAND: calculate which blocks we are writing. We have 835 * to write one block at a time to skip bad blocks. 836 */ 837 erasesize = blocklen; 838 } else { 839 erasesize = erase_len; 840 } 841 842 erase.length = erasesize; 843 844 /* This only runs once on NOR flash and SPI-dataflash */ 845 while (processed < write_total) { 846 rc = flash_bad_block (fd, mtd_type, &blockstart); 847 if (rc < 0) /* block test failed */ 848 return rc; 849 850 if (blockstart + erasesize > top_of_range) { 851 fprintf (stderr, "End of range reached, aborting\n"); 852 return -1; 853 } 854 855 if (rc) { /* block is bad */ 856 blockstart += blocklen; 857 continue; 858 } 859 860 erase.start = blockstart; 861 ioctl (fd, MEMUNLOCK, &erase); 862 863 /* Dataflash does not need an explicit erase cycle */ 864 if (mtd_type != MTD_DATAFLASH) 865 if (ioctl (fd, MEMERASE, &erase) != 0) { 866 fprintf (stderr, "MTD erase error on %s: %s\n", 867 DEVNAME (dev), 868 strerror (errno)); 869 return -1; 870 } 871 872 if (lseek (fd, blockstart, SEEK_SET) == -1) { 873 fprintf (stderr, 874 "Seek error on %s: %s\n", 875 DEVNAME (dev), strerror (errno)); 876 return -1; 877 } 878 879 #ifdef DEBUG 880 printf ("Write 0x%x bytes at 0x%llx\n", erasesize, blockstart); 881 #endif 882 if (write (fd, data + processed, erasesize) != erasesize) { 883 fprintf (stderr, "Write error on %s: %s\n", 884 DEVNAME (dev), strerror (errno)); 885 return -1; 886 } 887 888 ioctl (fd, MEMLOCK, &erase); 889 890 processed += blocklen; 891 block_seek = 0; 892 blockstart += blocklen; 893 } 894 895 if (write_total > count) 896 free (data); 897 898 return processed; 899 } 900 901 /* 902 * Set obsolete flag at offset - NOR flash only 903 */ 904 static int flash_flag_obsolete (int dev, int fd, off_t offset) 905 { 906 int rc; 907 struct erase_info_user erase; 908 909 erase.start = DEVOFFSET (dev); 910 erase.length = DEVESIZE (dev); 911 /* This relies on the fact, that obsolete_flag == 0 */ 912 rc = lseek (fd, offset, SEEK_SET); 913 if (rc < 0) { 914 fprintf (stderr, "Cannot seek to set the flag on %s \n", 915 DEVNAME (dev)); 916 return rc; 917 } 918 ioctl (fd, MEMUNLOCK, &erase); 919 rc = write (fd, &obsolete_flag, sizeof (obsolete_flag)); 920 ioctl (fd, MEMLOCK, &erase); 921 if (rc < 0) 922 perror ("Could not set obsolete flag"); 923 924 return rc; 925 } 926 927 static int flash_write (int fd_current, int fd_target, int dev_target) 928 { 929 int rc; 930 931 switch (environment.flag_scheme) { 932 case FLAG_NONE: 933 break; 934 case FLAG_INCREMENTAL: 935 (*environment.flags)++; 936 break; 937 case FLAG_BOOLEAN: 938 *environment.flags = active_flag; 939 break; 940 default: 941 fprintf (stderr, "Unimplemented flash scheme %u \n", 942 environment.flag_scheme); 943 return -1; 944 } 945 946 #ifdef DEBUG 947 printf ("Writing new environment at 0x%lx on %s\n", 948 DEVOFFSET (dev_target), DEVNAME (dev_target)); 949 #endif 950 rc = flash_write_buf(dev_target, fd_target, environment.image, 951 CUR_ENVSIZE, DEVOFFSET(dev_target), 952 DEVTYPE(dev_target)); 953 if (rc < 0) 954 return rc; 955 956 if (environment.flag_scheme == FLAG_BOOLEAN) { 957 /* Have to set obsolete flag */ 958 off_t offset = DEVOFFSET (dev_current) + 959 offsetof (struct env_image_redundant, flags); 960 #ifdef DEBUG 961 printf ("Setting obsolete flag in environment at 0x%lx on %s\n", 962 DEVOFFSET (dev_current), DEVNAME (dev_current)); 963 #endif 964 flash_flag_obsolete (dev_current, fd_current, offset); 965 } 966 967 return 0; 968 } 969 970 static int flash_read (int fd) 971 { 972 struct mtd_info_user mtdinfo; 973 int rc; 974 975 rc = ioctl (fd, MEMGETINFO, &mtdinfo); 976 if (rc < 0) { 977 perror ("Cannot get MTD information"); 978 return -1; 979 } 980 981 if (mtdinfo.type != MTD_NORFLASH && 982 mtdinfo.type != MTD_NANDFLASH && 983 mtdinfo.type != MTD_DATAFLASH) { 984 fprintf (stderr, "Unsupported flash type %u\n", mtdinfo.type); 985 return -1; 986 } 987 988 DEVTYPE(dev_current) = mtdinfo.type; 989 990 rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE, 991 DEVOFFSET (dev_current), mtdinfo.type); 992 993 return (rc != CUR_ENVSIZE) ? -1 : 0; 994 } 995 996 static int flash_io (int mode) 997 { 998 int fd_current, fd_target, rc, dev_target; 999 1000 /* dev_current: fd_current, erase_current */ 1001 fd_current = open (DEVNAME (dev_current), mode); 1002 if (fd_current < 0) { 1003 fprintf (stderr, 1004 "Can't open %s: %s\n", 1005 DEVNAME (dev_current), strerror (errno)); 1006 return -1; 1007 } 1008 1009 if (mode == O_RDWR) { 1010 if (HaveRedundEnv) { 1011 /* switch to next partition for writing */ 1012 dev_target = !dev_current; 1013 /* dev_target: fd_target, erase_target */ 1014 fd_target = open (DEVNAME (dev_target), mode); 1015 if (fd_target < 0) { 1016 fprintf (stderr, 1017 "Can't open %s: %s\n", 1018 DEVNAME (dev_target), 1019 strerror (errno)); 1020 rc = -1; 1021 goto exit; 1022 } 1023 } else { 1024 dev_target = dev_current; 1025 fd_target = fd_current; 1026 } 1027 1028 rc = flash_write (fd_current, fd_target, dev_target); 1029 1030 if (HaveRedundEnv) { 1031 if (close (fd_target)) { 1032 fprintf (stderr, 1033 "I/O error on %s: %s\n", 1034 DEVNAME (dev_target), 1035 strerror (errno)); 1036 rc = -1; 1037 } 1038 } 1039 } else { 1040 rc = flash_read (fd_current); 1041 } 1042 1043 exit: 1044 if (close (fd_current)) { 1045 fprintf (stderr, 1046 "I/O error on %s: %s\n", 1047 DEVNAME (dev_current), strerror (errno)); 1048 return -1; 1049 } 1050 1051 return rc; 1052 } 1053 1054 /* 1055 * s1 is either a simple 'name', or a 'name=value' pair. 1056 * s2 is a 'name=value' pair. 1057 * If the names match, return the value of s2, else NULL. 1058 */ 1059 1060 static char *envmatch (char * s1, char * s2) 1061 { 1062 if (s1 == NULL || s2 == NULL) 1063 return NULL; 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, CUR_ENVSIZE); 1093 if (addr0 == NULL) { 1094 fprintf(stderr, 1095 "Not enough memory for environment (%ld bytes)\n", 1096 CUR_ENVSIZE); 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, CUR_ENVSIZE); 1132 if (addr1 == NULL) { 1133 fprintf(stderr, 1134 "Not enough memory for environment (%ld bytes)\n", 1135 CUR_ENVSIZE); 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