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