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