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